The first enhanced version of Linux CAN-bus driver for OCERA project
authorppisa <ppisa>
Tue, 29 Apr 2003 22:40:59 +0000 (22:40 +0000)
committerppisa <ppisa>
Tue, 29 Apr 2003 22:40:59 +0000 (22:40 +0000)
can-0.7.1-pi3.5 (pisa@cmp.felk.cvut.cz)

33 files changed:
lincan/CREDITS
lincan/Makefile
lincan/README
lincan/TODO
lincan/include/can.h
lincan/include/constants.h
lincan/include/irq.h
lincan/include/main.h
lincan/include/pikronisa.h [new file with mode: 0644]
lincan/include/select.h [new file with mode: 0644]
lincan/src/Makefile [new file with mode: 0644]
lincan/src/bfadcan.c [new file with mode: 0644]
lincan/src/close.c
lincan/src/ioctl.c
lincan/src/irq.c
lincan/src/main.c
lincan/src/modparms.c
lincan/src/open.c
lincan/src/pc_i03.c [new file with mode: 0644]
lincan/src/pcm3680.c
lincan/src/pikronisa.c [new file with mode: 0644]
lincan/src/pip.c
lincan/src/proc.c
lincan/src/read.c
lincan/src/select.c [new file with mode: 0644]
lincan/src/setup.c
lincan/src/sja1000.c
lincan/src/sja1000p.c
lincan/utils/Makefile [new file with mode: 0644]
lincan/utils/can-proxy.c [new file with mode: 0644]
lincan/utils/readburst.c
lincan/utils/rxtx.c
lincan/utils/send.c [new file with mode: 0644]

index 7d84faa..781baf9 100644 (file)
@@ -4,3 +4,9 @@ I would like to thank all who have contributed to this project and especially:
 Tomasz Motylewski, T.Motylewski@bfad.de
 BFAD GmbH http://www.bfad.de/, http://www.getembedded.de/
        Tester, bugfixes, hints and PeliCAN mode!
+       He provided ETHERNET CAN-PROXY as well.
+
+Pavel Pisa, pisa@cmp.felk.cvut.cz
+http://cmp.felk.cvut.cz/~pisa, http://www.pikron.com
+       Bugfixes in SJA1000 code. Many other changes.
+       Most of new bugs belong to me.
\ No newline at end of file
index 75a1182..28722b9 100644 (file)
 # Written by Arnaud Westenberg email:arnaud@wanadoo.nl
 # This software is released under the GPL-License.
 # Version 0.7  6 Aug 2001
-
+#
+# Changes made by Pavel Pisa pisa@cmp.felk.cvut.cz as preliminary
+# study for OCERA Real Time CAN/CANOpen project ORTCAN
+#
 ########## The following options can be changed ##########
 
-# Include directory
-INCLUDEDIR = /usr/src/linux/include
 # Compiler
 CC = gcc
 # Enable debugging messages
 DEBUG = y 
-# Enable module version support
-MODVERSIONS = y 
-
-# You can comment out the hardware you don't need. This will result in a smaller
-# driver. By default, all hardware is supported in the driver. See the README 
-# file for a description of the supported hardware.
-PIP = y
-PCCAN = y      # Not to be confused with PCCCAN!!!
-SMARTCAN = y
-NSI = y
-CC104 = y
-AIM104 = y
-PCI03 = y
-PCM3680 = y
-M437 = y
-PCCCAN = y     # Not to be confused with PCCAN!!!
-SSV = y
-TEMPLATE = y
-
-########## Don't change anything under this line please ##########
-
-KERNEL_VERSION := $(shell awk -F\" '/REL/ {print $$2}' \
-       $(INCLUDEDIR)/linux/version.h | awk -F\- '{print $$1}')
-
-PROC_FS := $(shell awk -F\  '/PROC_FS/ {print $$3}' \
-       $(INCLUDEDIR)/linux/autoconf.h)
-
-VPATH = ./src:./include:./utils
-
-CFLAGS = -D__KERNEL__ -DMODULE -O2 -Wall -Wstrict-prototypes \
-       -Wpointer-arith -I $(INCLUDEDIR)
-       
-
-ifdef DEBUG
-       CFLAGS += -DCAN_DEBUG
-endif
-
-ifndef MODVERSIONS
-       CFLAGS += -DNOVER
-endif
-
-ifdef PROC_FS
-       SRCS += proc.c
-       OBJS += proc.o
-endif
-ifdef PIP
-       SRCS += pip.c
-       OBJS += pip.o
-endif
-ifdef PCCAN
-       SRCS += pccan.c
-       OBJS += pccan.o
-endif
-ifdef SMARTCAN
-       SRCS += smartcan.c
-       OBJS += smartcan.o
-endif
-ifdef NSI
-       SRCS += nsi.c
-       OBJS += nsi.o
-endif
-ifdef CC104
-       SRCS += cc_can104.c
-       OBJS += cc_can104.o
-endif
-ifdef PCI03
-       SRCS += pc-i03.c
-       OBJS += pc-i03.o
-endif
-ifdef PCM3680
-       SRCS += pcm3680.c
-       OBJS += pcm3680.o
-endif
-ifdef AIM104
-       SRCS += aim104.c
-       OBJS += aim104.o
-endif
-ifdef M437
-       SRCS += m437.c
-       OBJS += m437.o
-endif
-ifdef PCCCAN
-       SRCS += pcccan.c
-       OBJS += pcccan.o
-endif
-ifdef SSV
-       SRCS += ssv.c
-       OBJS += ssv.o
-endif
-ifdef TEMPLATE
-       SRCS += template.c
-       OBJS += template.o
-endif
-
-SRCS += main.c modparms.c setup.c sja1000.c i82527.c close.c ioctl.c\
-       open.c write.c read.c sja1000p.c irq.c
-
-OBJS += main.o modparms.o setup.o sja1000.o i82527.o close.o ioctl.o\
-       open.o write.o read.o sja1000p.o irq.o
-
-all : mesg main.ver can.o utils
-
-mesg :
-       @echo
-       @echo Compiling for kernel version: $(KERNEL_VERSION)
-ifdef MODVERSIONS
-       @echo Compiling with module version support
-else
-       @echo Compiling without module version support
-endif
-ifdef PROC_FS
-       @echo Compiling with proc filesystem support
-else
-       @echo Compiling without proc filesystem support
-endif
-       @echo
-
-ifdef MODVERSIONS
-main.ver : main.c
-       $(CC) -I $(INCLUDEDIR) -E -O2 -D__GENKSYMS__ $^ | \
-       /sbin/genksyms -k $(KERNEL_VERSION) > ./include/$@
-else
-main.ver:
-endif
-
-can.o : $(OBJS)
-       (cd ./src; ld -o ../can.o $(OBJS) -E -O2 -r)
-
-main.o : main.c main.h proc.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-proc.o : proc.c main.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-modparms.o : modparms.c modparms.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-setup.o : setup.c setup.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-pip.o : pip.c pip.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define PIP 1" >> .support
-pccan.o : pccan.c pccan.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define PCCAN 1" >> .support
-smartcan.o : smartcan.c smartcan.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define SMARTCAN 1" >> .support
-nsi.o : nsi.c nsi.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define NSI 1" >> .support
-cc_can104.o : cc_can104.c cc_can104.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define CC104 1" >> .support
-aim104.o : aim104.c aim104.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define AIM104 1" >> .support
-pc-i03.o : pc-i03.c pc-i03.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define PCI03 1" >> .support
-pcm3680.o : pcm3680.c pcm3680.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define PCM3680 1" >> .support
-m437.o : m437.c m437.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define M437 1" >> .support
-pcccan.o : pcccan.c pcccan.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define PCCCAN 1" >> .support
-ssv.o : ssv.c ssv.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define SSV 1" >> .support
-template.o : template.c template.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-       @echo "#define TEMPLATE 1" >> .support
-open.o : open.c open.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-i82527.o : i82527.c i82527.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-close.o : close.c close.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-read.o : read.c read.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-irq.o : irq.c irq.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-ioctl.o : ioctl.c ioctl.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-write.o : write.c write.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-sja1000.o : sja1000.c sja1000.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
-sja1000p.o : sja1000p.c sja1000p.h
-       $(CC) -c -o $(<D)/$@ $< $(CFLAGS)
 
-utils : rxtx sendburst readburst
+all: default
 
-rxtx : rxtx.c
-       $(CC) -o $(<D)/$@ $< -Wall
-sendburst : sendburst.c
-       $(CC) -o $(<D)/$@ $< -Wall
-readburst : readburst.c
-       $(CC) -o $(<D)/$@ $< -Wall
+.PHONY: dep default subdirs clean cleandepend
 
+dirs = src utils
 
-clean :
-       rm -f *.o
-       rm -f .support
-       (cd src; rm -f *.o)
-       (cd include; rm -f *.ver)
-       (cd utils; rm -f rxtx sendburst readburst)
+default dep clean install:
+       $(foreach dir, $(dirs), $(MAKE) -C $(dir) $@ ; )
index 0a8ffb8..f2095a8 100644 (file)
@@ -1,8 +1,38 @@
+Because we are not able to contact original author Arnaud Westenberg,
+and we have put piece of work to bugfixes and enhancements of the
+driver, we decided to offer our latest version to more tests.
+Please, if you know Arnaud's new address, contact us.
+Most of new bugs belongs to 
+
+    Pavel Pisa pisa@cmp.felk.cvut.cz 
+and Tomasz Motylewski, T.Motylewski@bfad.de
+
+Main enhancements:
+  interrupts service cleanup and partial redesign
+  deep module build redesign
+  support for select
+  preliminary support for 2.5.48 (UP only now)
+  CAN Ethernet proxy
+
+------------------------------------------------------------------------
+
 README for the linux CAN-bus driver.
 Written by Arnaud Westenberg email:arnaud@wanadoo.nl
 This software is released under the GPL-License.
 Version 0.7  6 Aug 2001
 
+Modified version can-0.7.1-pi2.2
+
+This version adds new Makefile system.
+DEVFS support
+Select/poll support for read/write events
+Preliminary cleanups for 2.5.xx kernels,
+it cannot work with SMP 2.5.xx until we get rid off
+CLI ans STI global directives
+
+Changes made by Pavel Pisa pisa@cmp.felk.cvut.cz as preliminary
+study for OCERA Real Time CAN/CANOpen project ORTCAN
+
 COMPILATION
 Just type 'make' at the command line and it should compile without errors.
 
@@ -27,6 +57,8 @@ The hw argument can be one of:
 - pc-i03, for the PC-I03 ISA card by IXXAT
 - pcm3680, for the PCM-3680 PC/104 card by Advantech
 - m437, for the M436 PC/104 card by SECO
+- bfadcan for sja1000 CAN embedded card made by BFAD GmbH
+- pikronisa for ISA memory mapped sja1000 CAN card made by PiKRON Ltd.
 - template, for yet unsupported hardware (you need to edit src/template.c)
 
 options can be one of:
@@ -36,6 +68,7 @@ options can be one of:
 - extended=[1|0], configures the driver to use extended message format.
 - pelican=[1|0], configures the driver to set the CAN chips into pelican mode.
 - baudrate=<nr>, sets the baudrate of the device(s)
+- clock_freq=<nr>, the frequency of the CAN quartz
 - stdmask=<nr>, sets the standard mask of the device
 - extmask=<nr>, sets the extended mask of the device
 - mo15mask=<nr>, sets the mask for message object 15 (i82527 only)
index f0d17cd..7a4c555 100644 (file)
@@ -3,8 +3,12 @@ Written by Arnaud Westenberg email:arnaud@wanadoo.nl
 This software is released under the GPL-License.
 Version 0.7  6 Aug 2001
 
++ Poll/select
+
 - Add proper comment to the code
 - Error handling/reporting
 - Proc directory
 - Lot of ioctl's
-- Poll/select
+
+- Get rid of CLI and STI, they are not longer supported
+  in 2.5.xx kernels
index 071deae..6ccb6dc 100644 (file)
@@ -13,7 +13,7 @@ struct canmsg_t {
        unsigned long   id;
        unsigned long   timestamp;
        unsigned int    length;
-       char            data[CAN_MSG_LENGTH];
+       unsigned char   data[CAN_MSG_LENGTH];
 } PACKED;
 
 /* Definitions to use for canmsg_t flags */
@@ -24,15 +24,15 @@ struct canmsg_t {
 /* CAN ioctl magic number */
 #define CAN_IOC_MAGIC 'd'
 
-unsigned long bittiming;
-unsigned short channel;
+typedef unsigned long bittiming_t;
+typedef unsigned short channel_t;
 
 /* CAN ioctl functions */
-#define CMD_START _IOW(CAN_IOC_MAGIC, 1, channel)
-#define CMD_STOP _IOW(CAN_IOC_MAGIC, 2, channel)
+#define CMD_START _IOW(CAN_IOC_MAGIC, 1, channel_t)
+#define CMD_STOP _IOW(CAN_IOC_MAGIC, 2, channel_t)
 //#define CMD_RESET 3
 
-#define CONF_BAUD _IOW(CAN_IOC_MAGIC, 4, bittiming)
+#define CONF_BAUD _IOW(CAN_IOC_MAGIC, 4, bittiming_t)
 //#define CONF_ACCM
 //#define CONF_XTDACCM
 //#define CONF_TIMING
index f662a98..10af2ce 100644 (file)
@@ -26,6 +26,7 @@
 #define MAX_HW_CARDS 8
 #define MAX_HW_CHIPS 4
 #define MAX_TOT_CHIPS (MAX_HW_CHIPS*MAX_HW_CARDS)
+#define MAX_TOT_CHIPS_STR 32   /* must be explicit for MODULE_PARM */
 #define MAX_IRQ 32
 #define MAX_MSGOBJS 15
 #define MAX_TOT_MSGOBJS (MAX_TOT_CHIPS*MAX_MSGOBJS)
@@ -39,6 +40,7 @@
 
 /* These flags can be used for the msgobj_t structure flags data entry */
 #define OPENED (1<<0)
+#define BUFFERS_ALLOCATED (1<<1)
 
 /* These flags can be used for the chip_t structure flags data entry */
 #define CONFIGURED (1<<0)
index 6391bf9..7410882 100644 (file)
@@ -7,3 +7,4 @@
 
 void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
 void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+void dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
index 53fb783..c811d87 100644 (file)
 
 #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 */
+
 #define MSG_OFFSET(object) ((object)*0x10)
 
 struct canhardware_t {
@@ -159,7 +167,7 @@ struct mem_addr {
  * The rx/tx_in_progress entries are used to determine whether the device is 
  * already set up for transmission.
  */
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 struct canfifo_t {
        struct wait_queue *readq, *writeq; 
        struct canmsg_t *buf_tx_entry;
@@ -170,7 +178,7 @@ struct canfifo_t {
        struct canmsg_t *rx_readp;
        int rx_size, tx_size;
        volatile int rx_in_progress, tx_in_progress;
-       int head, tail; //TEMP!!!
+       /*int head, tail;*/ /* removed */
 };
 #else
 struct canfifo_t {
@@ -184,7 +192,7 @@ struct canfifo_t {
        struct canmsg_t *rx_readp;
        int rx_size, tx_size;
        volatile int rx_in_progress, tx_in_progress;
-       int head, tail; //TEMP!!!
+       /*int head, tail;*/ /* removed */
 };
 #endif
 
@@ -192,7 +200,7 @@ struct canfifo_t {
 struct rtr_id {
        unsigned long id;
        struct canmsg_t *rtr_message;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
        struct wait_queue *rtr_wq;
 #else
        struct __wait_queue_head rtr_wq;
@@ -218,7 +226,7 @@ extern struct mem_addr *mem_head;
 /* Inline function to write to the hardware registers. The argument address is 
  * relative to the memory map of the chip and not the absolute memory address.
  */
-extern inline void can_write_reg(struct chip_t *chip, unsigned char data, unsigned short address)
+extern inline void can_write_reg(const struct chip_t *chip, unsigned char data, unsigned short address)
 {
        unsigned short segment_number;
        unsigned long address_to_write;
@@ -233,7 +241,7 @@ extern inline void can_write_reg(struct chip_t *chip, unsigned char data, unsign
        chip->hostdevice->hwspecops->write_register(data, address_to_write);
 }
 
-extern inline unsigned can_read_reg(struct chip_t *chip, unsigned short address)
+extern inline unsigned can_read_reg(const struct chip_t *chip, unsigned short address)
 {
        unsigned short segment_number;
        unsigned long address_to_read;
diff --git a/lincan/include/pikronisa.h b/lincan/include/pikronisa.h
new file mode 100644 (file)
index 0000000..7fa56dd
--- /dev/null
@@ -0,0 +1,21 @@
+/* pikronisa.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7  6 Aug 2001
+ *
+ * Support for PiKRON Ltd ISA CAN card using 
+ * memory mapped SJA1000 controller
+ * Added by Pavel Pisa pisa@cmp.felk.cvut.cz
+ */
+
+int pikronisa_request_io(unsigned long io_addr);
+int pikronisa_release_io(unsigned long io_addr);
+int pikronisa_reset(int card); 
+int pikronisa_init_hw_data(int card);
+int pikronisa_init_chip_data(int card, int chipnr);
+int pikronisa_init_obj_data(int chipnr, int objnr);
+void pikronisa_write_register(unsigned char data, unsigned long address);
+unsigned pikronisa_read_register(unsigned long address);
+int pikronisa_program_irq(int card);
+
diff --git a/lincan/include/select.h b/lincan/include/select.h
new file mode 100644 (file)
index 0000000..cdf9195
--- /dev/null
@@ -0,0 +1,10 @@
+/* select.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7.1-pi2  15 Nov 2002
+ * 
+ * added by Pavel Pisa pisa@cmp.felk.cvut.cz
+ */
+
+unsigned int can_poll(struct file *file, poll_table *wait);
diff --git a/lincan/src/Makefile b/lincan/src/Makefile
new file mode 100644 (file)
index 0000000..b83aa6d
--- /dev/null
@@ -0,0 +1,150 @@
+# Makefile for the Linux CAN-bus driver.
+# Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+# This software is released under the GPL-License.
+# Version 0.7  6 Aug 2001
+#
+# This version is adapted from uLan Communication driver
+# (C) Copyright 1999 by Pavel Pisa pisa@cmp.felk.cvut.cz
+#
+#*****************************************************************
+
+# Where to look for kernel
+# if not defined, sources of current running kernel are found
+#KERNEL_LOCATION=/usr/src/linux
+#KERNEL_LOCATION=/usr/src/linux-2.2.19
+#KERNEL_LOCATION=/usr/src/linux-2.2.22
+#KERNEL_LOCATION=/usr/src/linux-2.5.47
+
+# Comment-out next two lines, if you do not build driver 
+# in the OCERA source tree
+TOP=../../../../..
+KERNEL_LOCATION=$(TOP)/kernel/linux
+
+# Enable debugging messages
+DEBUG = y
+
+# You can comment out the hardware you don't need. This will result in a smaller
+# driver. By default, all hardware is supported in the driver. See the README 
+# file for a description of the supported hardware.
+#   pccan      Not to be confused with PCCCAN!!!
+#   pcccan     Not to be confused with PCCAN!!!
+
+SUPPORTED_CARDS = pip pccan smartcan nsi cc_can104 \
+                 pc_i03 pcm3680 aim104 m437 pcccan ssv \
+                 bfadcan pikronisa template
+
+########## Don't change anything under this line ################
+
+# currently running kernel
+CURRENT=$(shell uname -r)
+KERNEL_NEW=$(shell if [ -d /lib/modules/$(CURRENT)/build ] ; \
+               then echo yes ; else echo no ; fi )
+
+#KERNEL_LOCATION=/usr/src/kernel/$(CURRENT)
+#KERNEL_LOCATION=/lib/modules/$(CURRENT)/build
+
+ifndef KERNEL_LOCATION
+ifeq ($(KERNEL_NEW),yes)
+KERNEL_LOCATION=/lib/modules/$(CURRENT)/build
+MODULE_CHAR_LOC=/lib/modules/$(CURRENT)/kernel/drivers/char
+else
+KERNEL_LOCATION=/usr/src/linux
+MODULE_CHAR_LOC=/lib/modules/$(CURRENT)/misc
+endif
+endif
+
+KERNEL_VERSION := $(shell awk -F\" '/REL/ {print $$2}' \
+       $(KERNEL_LOCATION)/include/linux/version.h | awk -F\- '{print $$1}')
+
+PROC_FS := $(shell awk -F\  '/PROC_FS/ {print $$3}' \
+       $(KERNEL_LOCATION)/include/linux/autoconf.h)
+
+DEVFS_FS := $(shell awk -F\  '/DEVFS_FS/ {print $$3}' \
+       $(KERNEL_LOCATION)/include/linux/autoconf.h)
+
+KERNEL_MODULE_V26 := $(shell echo $(KERNEL_VERSION) \
+       | sed -n 's/^.*2\.[5-9]\..*$$/yes/p')
+
+ifdef DEBUG
+       EXTRA_CFLAGS += -DCAN_DEBUG
+       EXTRA_CFLAGS += -ggdb
+endif
+
+ifndef MODVERSIONS
+#      EXTRA_CFLAGS += -DNOVER
+#else
+#      EXTRA_CFLAGS += -DMODVERSIONS
+endif
+
+ifdef DEVFS_FS
+       EXTRA_CFLAGS += -DWITH_DEVFS_FS
+endif
+
+ifdef PROC_FS
+       O_OBJS += proc.o
+endif
+
+# Target object file if any
+# this must be undefined for 2.5.xx kernels
+ifndef KERNEL_MODULE_V26
+O_TARGET     = can.o
+endif
+# Regular object files
+O_OBJS      += $(SUPPORTED_CARDS:%=%.o)
+O_OBJS       += main.o modparms.o setup.o sja1000.o i82527.o close.o ioctl.o \
+               open.o write.o read.o sja1000p.o irq.o select.o
+# Objects with exported symbols (-DEXPORT_SYMTAB)
+OX_OBJS      = 
+# Module objects 
+M_OBJS       = $(O_TARGET)
+# Module only objects with exported symbols (-DEXPORT_SYMTAB)
+MX_OBJS      = 
+# Kernel only objects 
+L_OBJS       = 
+# Kernel only objects with exported symbols (-DEXPORT_SYMTAB)
+LX_OBJS      = 
+# Additional CFLAGS
+EXTRA_CFLAGS +=
+
+# Linux 2.4.2 build system needs next
+can-objs := $(O_OBJS)
+obj-y := $(O_OBJS)
+obj-m := can.o
+
+########## Source/target independent buil of module #############
+
+all : default
+
+default : make_this_module
+       cp can.o ../can.o
+
+dep: make_this_module_dep
+
+install : install_this_module
+
+.supported_cards.h: Makefile
+       echo >.supported_cards.h
+       $(foreach card, $(SUPPORTED_CARDS), \
+         echo \#define ENABLE_CARD_$(card) 1 >>.supported_cards.h ;)
+       
+make_this_module: .supported_cards.h
+       echo Linux kernel version $(KERNEL_VERSION)
+       echo Linux kernel sources $(KERNEL_LOCATION)
+       echo Module target $(obj-m)
+       echo Module objects $(can-objs)
+       DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR modules)
+       for f in $(obj-m:%.o=%) ; do if [ -f $$f.ko ] ; then cp -u $$f.ko $$f.o ; fi ; done
+
+make_this_module_dep:
+       DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR dep)
+
+install_this_module: make_this_module
+       su -c "mkdir -v -p $(MODULE_CHAR_LOC); cp -v $(obj-m) $(MODULE_CHAR_LOC)"
+
+clean:
+       rm -f $(M_OBJS) $(MX_OBJS) $(O_OBJS) $(OX_OBJS) $(obj-m) $(obj-m:%.o=%.ko) \
+                       .*.o.flags .*.o.cmd .depend .supported_cards.h *~
+
+ifndef KERNEL_MODULE_V26
+include $(KERNEL_LOCATION)/Rules.make
+endif
diff --git a/lincan/src/bfadcan.c b/lincan/src/bfadcan.c
new file mode 100644 (file)
index 0000000..930e91a
--- /dev/null
@@ -0,0 +1,342 @@
+/* bfadcan.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7  6 Aug 2001
+ */ 
+
+/* This file is intended as a bfadcan file for currently unsupported hardware.
+ * Once you've changed/added the functions specific to your hardware it is
+ * possible to load the driver with the hardware option hw=bfadcan.
+ */
+
+#define __NO_VERSION__ /* this is not a main module, do not include module info */
+
+#include <linux/autoconf.h>
+#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined (MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
+#include <asm/spinlock.h>
+#else
+#include <linux/spinlock.h>
+#endif
+
+#define WINDOWED_ACCESS
+
+#include "../include/main.h"
+#include "../include/i82527.h"
+#include "../include/sja1000p.h"
+
+long clock_freq;
+MODULE_PARM(clock_freq,"i");
+
+/* cli and sti are not allowed in 2.5.5x SMP kernels */
+#ifdef WINDOWED_ACCESS
+spinlock_t bfadcan_win_lock=SPIN_LOCK_UNLOCKED;
+#endif
+
+/*
+ * IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ */
+#ifdef WINDOWED_ACCESS
+#define IO_RANGE 0x4
+#else
+#define IO_RANGE 0x100
+#endif
+
+unsigned bfadcan_read_register(unsigned long address);
+void bfadcan_write_register(unsigned char data, unsigned long address);
+
+
+/**
+ * bfadcan_request_io: - reserve io memory
+ * @io_addr: The reserved memory starts at @io_addr, wich is the module 
+ * parameter @io.
+ *
+ * The function bfadcan_request_io() is used to reserve the io-memory. If your
+ * hardware uses a dedicated memory range as hardware control registers you
+ * will have to add the code to reserve this memory as well. 
+ * %IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/bfadcan.c
+ */
+int bfadcan_request_io(unsigned long io_addr)
+{
+       if (check_region(io_addr,IO_RANGE)) {
+               CANMSG("Unable to open port: 0x%lx\n",io_addr);
+               return -ENODEV;
+       }
+       else {
+               request_region(io_addr,IO_RANGE,DEVICE_NAME);
+               DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1);
+       }
+       return 0;
+}
+
+/**
+ * bfadcan_release_io - free reserved io-memory
+ * @io_addr: Start of the memory range to be released.
+ *
+ * The function bfadcan_release_io() is used to free reserved io-memory.
+ * In case you have reserved more io memory, don't forget to free it here.
+ * IO_RANGE is the io-memory range that gets released, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function always returns zero
+ * File: src/bfadcan.c
+ */
+int bfadcan_release_io(unsigned long io_addr)
+{
+       release_region(io_addr,IO_RANGE);
+
+       return 0;
+}
+
+/**
+ * bfadcan_reset - hardware reset routine
+ * @card: Number of the hardware card.
+ *
+ * The function bfadcan_reset() is used to give a hardware reset. This is 
+ * rather hardware specific so I haven't included example code. Don't forget to 
+ * check the reset status of the chip before returning.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/bfadcan.c
+ */
+int bfadcan_reset(int card)
+{
+
+       int i;
+       struct chip_t *chip=candevices_p[card]->chip[0];
+       unsigned cdr;
+       
+       bfadcan_write_register(MOD_RM, chip->chip_base_addr+SJAMOD);
+       udelay(1000);
+       
+       cdr=bfadcan_read_register(chip->chip_base_addr+SJACDR);
+       bfadcan_write_register(cdr|CDR_PELICAN, chip->chip_base_addr+SJACDR);
+
+       bfadcan_write_register(0, chip->chip_base_addr+SJAIER);
+
+       i=20;
+       bfadcan_write_register(0, chip->chip_base_addr+SJAMOD);
+       while (bfadcan_read_register(chip->chip_base_addr+SJAMOD)&MOD_RM){
+               if(!i--) return -ENODEV;
+               udelay(1000);
+               bfadcan_write_register(0, chip->chip_base_addr+SJAMOD);
+       }
+
+       cdr=bfadcan_read_register(chip->chip_base_addr+SJACDR);
+       bfadcan_write_register(cdr|CDR_PELICAN, chip->chip_base_addr+SJACDR);
+
+       bfadcan_write_register(0, chip->chip_base_addr+SJAIER);
+       
+       return 0;
+}
+
+#define RESET_ADDR 0x202
+#define NR_82527 0
+#define NR_SJA1000 1
+
+/**
+ * bfadcan_init_hw_data - Initialze hardware cards
+ * @card: Number of the hardware card.
+ *
+ * The function bfadcan_init_hw_data() is used to initialize the hardware
+ * structure containing information about the installed CAN-board.
+ * %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 hardware uses programmable interrupts.
+ * Return Value: The function always returns zero
+ * File: src/bfadcan.c
+ */
+int bfadcan_init_hw_data(int card) 
+{
+       candevices_p[card]->res_addr=RESET_ADDR;
+       candevices_p[card]->nr_82527_chips=NR_82527;
+       candevices_p[card]->nr_sja1000_chips=NR_SJA1000;
+       candevices_p[card]->flags |= 0 /* PROGRAMMABLE_IRQ */ ;
+
+       return 0;
+}
+
+#define CHIP_TYPE "sja1000p"
+/**
+ * bfadcan_init_chip_data - Initialize chips
+ * @card: Number of the hardware card
+ * @chipnr: Number of the CAN chip on the hardware card
+ *
+ * The function bfadcan_init_chip_data() is used to initialize the hardware
+ * structure containing information about the CAN chips.
+ * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
+ * "sja1000".
+ * The @chip_base_addr entry represents the start of the 'official' memory map
+ * of the installed chip. It's likely that this is the same as the @io_addr
+ * argument supplied at module loading time.
+ * The @clock entry holds the chip clock value in Hz.
+ * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
+ * register. Options defined in the %sja1000.h file:
+ * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN
+ * The entry @sja_ocr_reg holds hardware specific options for the Output Control
+ * register. Options defined in the %sja1000.h file:
+ * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK,
+ * %OCR_TX0_LH, %OCR_TX1_ZZ.
+ * The entry @int_clk_reg holds hardware specific options for the Clock Out
+ * register. Options defined in the %i82527.h file:
+ * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
+ * The entry @int_bus_reg holds hardware specific options for the Bus 
+ * Configuration register. Options defined in the %i82527.h file:
+ * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
+ * The entry @int_cpu_reg holds hardware specific options for the cpu interface
+ * register. Options defined in the %i82527.h file:
+ * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST.
+ * Return Value: The function always returns zero
+ * File: src/bfadcan.c
+ */
+int bfadcan_init_chip_data(int card, int chipnr)
+{
+       unsigned int id1, id2;
+       candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE;
+       candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr;
+       candevices_p[card]->chip[chipnr]->clock = clock_freq;
+       candevices_p[card]->chip[chipnr]->int_cpu_reg = iCPU_DSC;
+       candevices_p[card]->chip[chipnr]->int_clk_reg = iCLK_SL1;
+       candevices_p[card]->chip[chipnr]->int_bus_reg = iBUS_CBY;
+       candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF;
+       candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL |
+                                                               OCR_TX0_LH;
+       id1 = inb(0xe284);
+       id2 = inb(0xe285);
+
+
+       CANMSG("can driver ver 0.7.1-tm5, at %04lx, CPLD v%d.%d.%d.%d\n",
+                                       candevices_p[card]->chip[chipnr]->chip_base_addr,
+                                                       id1>>4, id1&0x0f, id2>>4, id2&0x0f);
+
+
+       return 0;
+}
+
+/**
+ * bfadcan_init_obj_data - Initialize message buffers
+ * @chipnr: Number of the CAN chip
+ * @objnr: Number of the message buffer
+ *
+ * The function bfadcan_init_obj_data() is used to initialize the hardware
+ * structure containing information about the different message objects on the
+ * CAN chip. In case of the sja1000 there's only one message object but on the
+ * i82527 chip there are 15.
+ * The code below is for a i82527 chip and initializes the object base addresses
+ * The entry @obj_base_addr represents the first memory address of the message 
+ * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
+ * base address.
+ * Unless the hardware uses a segmented memory map, flags can be set zero.
+ * Return Value: The function always returns zero
+ * File: src/bfadcan.c
+ */
+int bfadcan_init_obj_data(int chipnr, int objnr)
+{
+       chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr+(objnr+1)*0x10;
+       chips_p[chipnr]->msgobj[objnr]->flags=0;
+       
+       return 0;
+}
+
+/**
+ * bfadcan_program_irq - program interrupts
+ * @card: Number of the hardware card.
+ *
+ * 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 
+ * 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
+ * File: src/bfadcan.c
+ */
+int bfadcan_program_irq(int card)
+{
+       return 0;
+}
+
+/**
+ * bfadcan_write_register - Low level write register routine
+ * @data: data to be written
+ * @address: memory address to write to
+ *
+ * The function bfadcan_write_register() is used to write to hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific write process.
+ * Return Value: The function does not return a value
+ * File: src/bfadcan.c
+ */
+void bfadcan_write_register(unsigned char data, unsigned long address)
+{
+#ifdef WINDOWED_ACCESS
+       long flags;
+       spin_lock_irqsave(&bfadcan_win_lock,flags);
+       outb(address&0x00ff,0x200);
+       outb(data, 0x201);
+       spin_unlock_irqrestore(&bfadcan_win_lock,flags);
+#else
+       outb(data,address);
+#endif
+}
+
+/**
+ * bfadcan_read_register - Low level read register routine
+ * @address: memory address to read from
+ *
+ * The function bfadcan_read_register() is used to read from hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific read process.
+ * Return Value: The function returns the value stored in @address
+ * File: src/bfadcan.c
+ */
+unsigned bfadcan_read_register(unsigned long address)
+{
+#ifdef WINDOWED_ACCESS
+       long flags;
+       int ret;
+       spin_lock_irqsave(&bfadcan_win_lock,flags);
+       outb(address&0x00ff,0x200);
+       ret = inb(0x201);
+       spin_unlock_irqrestore(&bfadcan_win_lock,flags);
+       return ret;
+#else
+       return inb(address);
+#endif
+}
+
+/* !!! Don't change this function !!! */
+int bfadcan_register(struct hwspecops_t *hwspecops)
+{
+       hwspecops->request_io = bfadcan_request_io;
+       hwspecops->release_io = bfadcan_release_io;
+       hwspecops->reset = bfadcan_reset;
+       hwspecops->init_hw_data = bfadcan_init_hw_data;
+       hwspecops->init_chip_data = bfadcan_init_chip_data;
+       hwspecops->init_obj_data = bfadcan_init_obj_data;
+       hwspecops->write_register = bfadcan_write_register;
+       hwspecops->read_register = bfadcan_read_register;
+       hwspecops->program_irq = bfadcan_program_irq;
+       return 0;
+}
index 7ac3574..5f7d112 100644 (file)
@@ -26,6 +26,7 @@
 
 int can_close(struct inode *inode, struct file *file)
 {
+       objects_p[MINOR_NR]->flags &= ~BUFFERS_ALLOCATED;
        /* Give up message buffer memory */
        if (objects_p[MINOR_NR]->fifo->buf_tx_entry)
                del_mem_from_list(objects_p[MINOR_NR]->fifo->buf_tx_entry);
@@ -39,7 +40,8 @@ int can_close(struct inode *inode, struct file *file)
 /* FIXME: what about clearing chip HW status, stopping sending messages etc? */
        
        objects_p[MINOR_NR]->flags &= ~OPENED;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
        MOD_DEC_USE_COUNT;
-
+#endif
        return 0;
 }
index 0f54c86..ec029ab 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/fs.h>
 #include <linux/version.h>
+#include <linux/string.h>
 
 #include "../include/main.h"
 #include "../include/ioctl.h"
@@ -81,7 +82,7 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
                        fifo->rx_size= MAX_BUF_LENGTH * sizeof(struct canmsg_t);
                        fifo->tx_size = fifo->rx_size;
 
-                       #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+                       #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
                                init_waitqueue(&fifo->readq);
                                init_waitqueue(&fifo->writeq);
                        #else
@@ -92,8 +93,6 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
                        fifo->rx_in_progress = 0;
                        fifo->tx_in_progress = 0;
 
-                       fifo->head = fifo->tail = 0; //TEMP!!
-                       
                        break;
                }
 
index 92ce53e..caf0ac6 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/sched.h>
 #include <linux/version.h>
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 #include <asm/spinlock.h>
 #else
 #include <linux/spinlock.h>
 #include "../include/i82527.h"
 #include "../include/sja1000.h"
 
-void i82527_irq_rtr_handler(void);
-void sja1000_irq_read_handler(void);
-void sja1000_irq_write_handler(void);
+void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *msgobj, 
+                           struct rtr_id *rtr_search, unsigned long message_id);
+void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj);
+void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj);
 
-void (*put_reg)(unsigned char data, unsigned long address);
-unsigned (*get_reg)(unsigned long address);
-
-struct chip_t *chip=NULL;
-struct candevice_t *device=NULL;
+/*struct candevice_t *device=NULL;
 unsigned object=0,irq_register=0;
 unsigned long msgbase=0;
 struct canfifo_t *fifo=NULL;
 unsigned long message_id=0;
 struct rtr_id *rtr_search;
+*/
 
-inline void i82527_irq_write_handler(void)
+inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj)
 {
-       put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0);
+       struct canfifo_t *fifo=msgobj->fifo;
+       unsigned long msgbase=msgobj->obj_base_addr;
+       void (*write_reg)(unsigned char data, unsigned long address);
+       unsigned (*read_reg)(unsigned long address);
+       write_reg=chip->hostdevice->hwspecops->write_register;
+       read_reg=chip->hostdevice->hwspecops->read_register;
+
+       (*write_reg)((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0);
 
        fifo->tx_readp++;
        if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
@@ -53,43 +58,48 @@ inline void i82527_irq_write_handler(void)
        if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty
                fifo->tx_in_progress = 0;
                if (waitqueue_active(&fifo->writeq)) {
-                       chip->msgobj[object]->ret = 0;
+                       msgobj->ret = 0;
                        wake_up_interruptible(&fifo->writeq);
                }
                return;
        }
-       if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object],
-                                                       fifo->tx_readp)) {
+       if (chip->chipspecops->pre_write_config(chip, msgobj, fifo->tx_readp)) {
                if (waitqueue_active(&fifo->writeq)) {
-                       chip->msgobj[object]->ret = -1;
+                       msgobj->ret = -1;
                        wake_up_interruptible(&fifo->writeq);
                        return;
                }
        }
-       if (chip->chipspecops->send_msg(chip, chip->msgobj[object],
-                                                       fifo->tx_readp)) {
+       if (chip->chipspecops->send_msg(chip, msgobj, fifo->tx_readp)) {
                if (waitqueue_active(&fifo->writeq)) {
-                       chip->msgobj[object]->ret = -1;
+                       msgobj->ret = -1;
                        wake_up_interruptible(&fifo->writeq);
                        return;
                }
        } 
 }
 
-inline void i82527_irq_read_handler(void)
+inline void i82527_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj,
+                                   unsigned long message_id)
 {
        int i=0, tmp=1 ;
-
+       struct canfifo_t *fifo=msgobj->fifo;
+       unsigned long msgbase=msgobj->obj_base_addr;
+       void (*write_reg)(unsigned char data, unsigned long address);
+       unsigned (*read_reg)(unsigned long address);
+       write_reg=chip->hostdevice->hwspecops->write_register;
+       read_reg=chip->hostdevice->hwspecops->read_register;
+       
        while (tmp) {
-               put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase +
+               (*write_reg)((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase +
                                                                iMSGCTL1);
-               put_reg((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase +
+               (*write_reg)((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase +
                                                                iMSGCTL0);
 
-               fifo->rx_writep->length =(get_reg(msgbase+iMSGCFG) & 0xf0) >> 4;
+               fifo->rx_writep->length =((*read_reg)(msgbase+iMSGCFG) & 0xf0) >> 4;
                fifo->rx_writep->id = message_id;
                for (i=0; i < fifo->rx_writep->length; i++)
-                       fifo->rx_writep->data[i] = get_reg(msgbase+iMSGDAT0+i);
+                       fifo->rx_writep->data[i] = (*read_reg)(msgbase+iMSGDAT0+i);
 
 //FIXME: Add buffer overflow check, currently it's silently over written!
 
@@ -97,7 +107,7 @@ inline void i82527_irq_read_handler(void)
                if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH)
                        fifo->rx_writep = fifo->buf_rx_entry;
 
-               if (!((tmp=get_reg(msgbase + iMSGCTL1)) & NEWD_SET)) {
+               if (!((tmp=(*read_reg)(msgbase + iMSGCTL1)) & NEWD_SET)) {
                        break;
                }
 
@@ -114,21 +124,30 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
        int id0=0, id1=0, id2=0, id3=0;
 
-       chip=(struct chip_t *)dev_id;
-       device=(struct candevice_t *)chip->hostdevice;
-
-       put_reg=device->hwspecops->write_register;
-       get_reg=device->hwspecops->read_register;
+       unsigned irq_register;
+       unsigned object;
+       struct chip_t *chip=(struct chip_t *)dev_id;
+       struct msgobj_t *msgobj;
+       unsigned long msgbase;
+       unsigned long message_id;
+       struct rtr_id *rtr_search;
+       void (*write_reg)(unsigned char data, unsigned long address);
+       unsigned (*read_reg)(unsigned long address);
+       write_reg=chip->hostdevice->hwspecops->write_register;
+       read_reg=chip->hostdevice->hwspecops->read_register;
+
+       /*put_reg=device->hwspecops->write_register;*/
+       /*get_reg=device->hwspecops->read_register;*/
 
        if ( (chip->flags & SEGMENTED) != 0)
-               irq_register = get_reg(chip->chip_base_addr+iIRQ+SPACING);
+               irq_register = can_read_reg(chip, iIRQ+SPACING);
        else 
-               irq_register = get_reg(chip->chip_base_addr+iIRQ);
+               irq_register = can_read_reg(chip, iIRQ);
 
        while (irq_register) {
 
                if (irq_register == 0x01) {
-                       DEBUGMSG("Status register: 0x%x\n",get_reg(chip->chip_base_addr+iSTAT));
+                       DEBUGMSG("Status register: 0x%x\n",can_read_reg(chip, iSTAT));
                        return;
                }
                
@@ -137,24 +156,24 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
                else
                        object = irq_register-3;
 
-               fifo=chip->msgobj[object]->fifo;
-               msgbase=chip->msgobj[object]->obj_base_addr;
+               msgobj=chip->msgobj[object];
+               msgbase=msgobj->obj_base_addr;
 
-               if (get_reg(msgbase+iMSGCFG) & MCFG_DIR) {
-                       i82527_irq_write_handler(); 
+               if ((*read_reg)(msgbase+iMSGCFG) & MCFG_DIR) {
+                       i82527_irq_write_handler(chip, msgobj); 
                }
                else { 
 
                        if (extended) {
-                               id0=get_reg(msgbase+iMSGID3);
-                               id1=get_reg(msgbase+iMSGID2)<<8;
-                               id2=get_reg(msgbase+iMSGID1)<<16;
-                               id3=get_reg(msgbase+iMSGID0)<<24;
+                               id0=(*read_reg)(msgbase+iMSGID3);
+                               id1=(*read_reg)(msgbase+iMSGID2)<<8;
+                               id2=(*read_reg)(msgbase+iMSGID1)<<16;
+                               id3=(*read_reg)(msgbase+iMSGID0)<<24;
                                message_id=(id0|id1|id2|id3)>>3;
                        }
                        else {
-                               id0=get_reg(msgbase+iMSGID1);
-                               id1=get_reg(msgbase+iMSGID0)<<8;
+                               id0=(*read_reg)(msgbase+iMSGID1);
+                               id1=(*read_reg)(msgbase+iMSGID0)<<8;
                                message_id=(id0|id1)>>5;
                        }
 
@@ -167,32 +186,38 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
                        }
                        spin_unlock(&hardware_p->rtr_lock);
                        if ((rtr_search!=NULL) && (rtr_search->id==message_id))
-                               i82527_irq_rtr_handler();
+                               i82527_irq_rtr_handler(chip, msgobj, rtr_search, message_id);
                        else
-                               i82527_irq_read_handler(); 
+                               i82527_irq_read_handler(chip, msgobj, message_id); 
                }
 
                if ( (chip->flags & SEGMENTED) != 0)
-                       irq_register=get_reg(chip->chip_base_addr+iIRQ+SPACING);
+                       irq_register=can_read_reg(chip, iIRQ+SPACING);
                else
-                       irq_register=get_reg(chip->chip_base_addr+iIRQ);
+                       irq_register=can_read_reg(chip, iIRQ);
        }
        
 }
 
-void i82527_irq_rtr_handler(void)
+void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *msgobj,
+                           struct rtr_id *rtr_search, unsigned long message_id)
 {
        short int i=0;
-
-       put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0);
-       put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1);
+       unsigned long msgbase=msgobj->obj_base_addr;
+       void (*write_reg)(unsigned char data, unsigned long address);
+       unsigned (*read_reg)(unsigned long address);
+       write_reg=chip->hostdevice->hwspecops->write_register;
+       read_reg=chip->hostdevice->hwspecops->read_register;
+
+       (*write_reg)((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0);
+       (*write_reg)((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1);
        
        spin_lock(&hardware_p->rtr_lock);
 
        rtr_search->rtr_message->id=message_id;
-       rtr_search->rtr_message->length=(get_reg(msgbase + iMSGCFG) & 0xf0)>>4;
+       rtr_search->rtr_message->length=((*read_reg)(msgbase + iMSGCFG) & 0xf0)>>4;
        for (i=0; i<rtr_search->rtr_message->length; i++)
-               rtr_search->rtr_message->data[i]=get_reg(msgbase+iMSGDAT0+i);
+               rtr_search->rtr_message->data[i]=(*read_reg)(msgbase+iMSGDAT0+i);
        
        spin_unlock(&hardware_p->rtr_lock);
 
@@ -202,33 +227,32 @@ void i82527_irq_rtr_handler(void)
 
 void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-       chip=(struct chip_t *)dev_id;
-       device=(struct candevice_t *)chip->hostdevice;
-
-       put_reg=device->hwspecops->write_register;
-       get_reg=device->hwspecops->read_register;
+       unsigned irq_register;
+       struct chip_t *chip=(struct chip_t *)dev_id;
+       struct msgobj_t *msgobj;
+       struct canfifo_t *fifo;
 
-       irq_register=get_reg(chip->chip_base_addr+SJAIR);
+       irq_register=can_read_reg(chip, SJAIR);
 //     DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);
 //     DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n",
-//                                     get_reg(chip->chip_base_addr+SJASR));
+//                                     can_read_reg(chip, SJASR));
 
        if ((irq_register & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0)
                return;
 
-       fifo=chip->msgobj[0]->fifo;
-       msgbase=chip->msgobj[0]->obj_base_addr;
+       msgobj=chip->msgobj[0];
+       fifo=msgobj->fifo;
 
        if ((irq_register & IR_RI) != 0) 
-               sja1000_irq_read_handler();
+               sja1000_irq_read_handler(chip, msgobj);
        if ((irq_register & IR_TI) != 0) 
-               sja1000_irq_write_handler();
+               sja1000_irq_write_handler(chip, msgobj);
        if ((irq_register & (IR_EI|IR_DOI)) != 0) { 
                // Some error happened
 // FIXME: chip should be brought to usable state. Transmission cancelled if in progress.
 // Reset flag set to 0 if chip is already off the bus. Full state report
                CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n",
-                       get_reg(chip->chip_base_addr+SJASR), irq_register);
+                       can_read_reg(chip, SJASR), irq_register);
                chip->msgobj[0]->ret=-1;
                if (waitqueue_active(&fifo->writeq))
                        wake_up_interruptible(&fifo->writeq);
@@ -238,61 +262,66 @@ void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 
        return;
 }
-void sja1000_irq_read_handler(void)
+
+void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj)
 {
-       int i=0, id=0, tmp=1;
+       int i=0, id=0;
+       struct canfifo_t *fifo=msgobj->fifo;
 
-       while (tmp) {
-               id = get_reg(msgbase+SJARXID0) | (get_reg(msgbase+SJARXID1)<<8);
-               fifo->buf_rx_entry[fifo->head].length = id & 0x0f;
-               fifo->buf_rx_entry[fifo->head].flags = id&ID0_RTR ? MSG_RTR : 0;
-               fifo->buf_rx_entry[fifo->head].timestamp = 0;
-               fifo->buf_rx_entry[fifo->head].cob = 0;
-               fifo->buf_rx_entry[fifo->head].id = id>>5;
+       do {
+               id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8);
+               fifo->rx_writep->length = id & 0x0f;
+               fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0;
+               fifo->rx_writep->timestamp = 0;
+               fifo->rx_writep->cob = 0;
+               fifo->rx_writep->id = id>>5;
 
-               for (i=0; i<fifo->buf_rx_entry[fifo->head].length; i++)
-                       fifo->buf_rx_entry[fifo->head].data[i]=get_reg(msgbase +
-                                                               SJARXDAT0 + i);
+               for (i=0; i<fifo->rx_writep->length; i++)
+                       fifo->rx_writep->data[i]=can_read_reg(chip, SJARXDAT0 + i);
 
-               put_reg(CMR_RRB,msgbase+SJACMR);
+               can_write_reg(chip, CMR_RRB, SJACMR);
 
-               fifo->head++;
-               if (fifo->head >= MAX_BUF_LENGTH-1)
-                       fifo->head=0;
+               fifo->rx_writep++;
+               if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH)
+                       fifo->rx_writep = fifo->buf_rx_entry;
+
+       } while(can_read_reg(chip, SJASR) & SR_RBS);
 
-               tmp=(get_reg(msgbase+SJASR) & SR_RBS);
-       }
        if (waitqueue_active(&fifo->readq))
                wake_up_interruptible(&fifo->readq);
 }
 
-void sja1000_irq_write_handler(void)
+void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj)
 {
+       struct canfifo_t *fifo=msgobj->fifo;
+
        fifo->tx_readp++;
        if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
                fifo->tx_readp = fifo->buf_tx_entry;
        if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty
                fifo->tx_in_progress = 0;
                if (waitqueue_active(&fifo->writeq)) {
-                       chip->msgobj[object]->ret = 0;
+                       msgobj->ret = 0;
                        wake_up_interruptible(&fifo->writeq);
                }
                return;
        }
-       if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object],
-                                                       fifo->tx_readp)) {
+       if (chip->chipspecops->pre_write_config(chip, msgobj, fifo->tx_readp)) {
                if (waitqueue_active(&fifo->writeq)) {
-                       chip->msgobj[object]->ret = -1;
+                       msgobj->ret = -1;
                        wake_up_interruptible(&fifo->writeq);
                        return;
                }
        }
-       if (chip->chipspecops->send_msg(chip, chip->msgobj[object],
-                                                       fifo->tx_readp)) {
+       if (chip->chipspecops->send_msg(chip, msgobj, fifo->tx_readp)) {
                if (waitqueue_active(&fifo->writeq)) {
-                       chip->msgobj[object]->ret = -1;
+                       msgobj->ret = -1;
                        wake_up_interruptible(&fifo->writeq);
                        return;
                }
        }
 }
+
+void dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
+       CANMSG("dummy_irq_handler called irq %d \n", irq);
+}
index 4ff1523..f21e78f 100644 (file)
 #include <linux/fs.h>
 #include <linux/wrapper.h>
 #include <linux/sched.h>
+#include <linux/poll.h>
 #include <linux/version.h>
 #include <linux/autoconf.h>
+#include <linux/interrupt.h>
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 #include <asm/spinlock.h>
 #else
 #include <linux/spinlock.h>
 #if !defined (__GENKSYMS__) 
 #if (defined (MODVERSIONS) && !defined(NOVER))
 #include <linux/modversions.h>
-#include "../include/main.ver"
+/*#include "../include/main.ver"*/
 #endif
 #endif
 
+#ifdef CONFIG_DEVFS_FS
+#include <linux/miscdevice.h>
+#endif
+
 #include "../include/main.h"
 #include "../include/modparms.h"
 #include "../include/setup.h"
@@ -45,6 +51,7 @@
 #include "../include/open.h"
 #include "../include/close.h"
 #include "../include/read.h"
+#include "../include/select.h"
 #include "../include/irq.h"
 #include "../include/ioctl.h"
 #include "../include/write.h"
@@ -55,7 +62,8 @@
 int major=CAN_MAJOR;
 MODULE_PARM(major,"1i");
 int minor[MAX_TOT_CHIPS]={-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};
-MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i");
+/*MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i");*/
+MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i");
 int extended=0;
 MODULE_PARM(extended,"1i");
 int pelican=0;
@@ -75,26 +83,40 @@ MODULE_PARM(extmask, "1i");
 int mo15mask=0;
 MODULE_PARM(mo15mask, "1i");
 
+/* Other module attributes */
+#ifdef MODULE_SUPPORTED_DEVICE
+MODULE_SUPPORTED_DEVICE("can");
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef MODULE_DESCRIPTION
+MODULE_DESCRIPTION("Universal Linux CAN-bus device driver");
+#endif
+
 /* Global structures, used to describe the installed hardware. */
 struct canhardware_t canhardware;
 struct canhardware_t *hardware_p=&canhardware;
 struct candevice_t *candevices_p[MAX_HW_CARDS];
 struct chip_t *chips_p[MAX_TOT_CHIPS];
 struct msgobj_t *objects_p[MAX_TOT_MSGOBJS];
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t  devfs_handles[MAX_TOT_MSGOBJS];
+#endif
 
 /* Pointers to dynamically allocated memory are maintained in a linked list
  * to ease memory deallocation.
  */
 struct mem_addr *mem_head=NULL;
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 struct file_operations can_fops=
 {
        NULL,                           /* llseek */
        read:           can_read,
        write:          can_write,
        NULL,                           /* readdir */
-       NULL,                           /* poll */
+       poll:           can_poll,
        ioctl:          can_ioctl,
        NULL,                           /* mmap */
        open:           can_open,
@@ -108,6 +130,7 @@ struct file_operations can_fops=
        owner:          THIS_MODULE,    
        read:           can_read,
        write:          can_write,
+       poll:           can_poll,
        ioctl:          can_ioctl,
        open:           can_open,
        release:        can_close,
@@ -146,6 +169,9 @@ int init_module(void)
                        goto reset_error;
        }
 
+       spin_lock_init(&hardware_p->rtr_lock);
+       hardware_p->rtr_queue=NULL;
+
        i=0;
        while ( (chips_p[i] != NULL) && (i < MAX_TOT_CHIPS) ) {
                if (!strcmp(chips_p[i]->chip_type,"i82527")) {
@@ -171,14 +197,26 @@ int init_module(void)
                                goto interrupt_error;
        }
 
-       spin_lock_init(&hardware_p->rtr_lock);
-       hardware_p->rtr_queue=NULL;
-
 #ifdef CONFIG_PROC_FS
        if (can_init_procdir())
                goto proc_error;
 #endif
 
+#ifdef CONFIG_DEVFS_FS
+        {
+               char dev_name[32];
+               int dev_minor;
+               for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+                       if(!objects_p[i]) continue;
+                       dev_minor=objects_p[i]->minor;
+                       sprintf (dev_name, "can%d", dev_minor);
+                       devfs_handles[i]=devfs_register(NULL, dev_name,
+                               DEVFS_FL_DEFAULT, major, dev_minor,
+                               S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+                               &can_fops, (void*)objects_p[i]);
+               }
+        }
+#endif
        return 0;
 
 #ifdef CONFIG_PROC_FS
@@ -218,6 +256,13 @@ void cleanup_module(void)
                CANMSG("Error unregistering /proc/can entry.\n"); 
 #endif
 
+#ifdef CONFIG_DEVFS_FS
+               for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+                       if(devfs_handles[i])
+                               devfs_unregister(devfs_handles[i]);
+               }
+#endif
+        i=0;
        while ( (chips_p[i] != NULL) & (i < MAX_TOT_CHIPS) ) {
                free_irq(chips_p[i]->chip_irq, chips_p[i]);
                i++;
index 6f9a0de..cf4a325 100644 (file)
 #include <linux/modversions.h>
 #endif
 
-#include "../.support"
-#ifndef PIP
-#define PIP 0
+#include ".supported_cards.h"
+
+#ifndef ENABLE_CARD_pip
+#define ENABLE_CARD_pip 0
+#endif
+#ifndef ENABLE_CARD_smartcan
+#define ENABLE_CARD_smartcan 0
+#endif
+#ifndef ENABLE_CARD_pccan
+#define ENABLE_CARD_pccan 0
 #endif
-#ifndef SMARTCAN
-#define SMARTCAN 0
+#ifndef ENABLE_CARD_nsi
+#define ENABLE_CARD_nsi 0
 #endif
-#ifndef PCCAN
-#define PCCAN 0
+#ifndef ENABLE_CARD_cc_can104
+#define ENABLE_CARD_cc_can104 0
 #endif
-#ifndef NSI
-#define NSI 0
+#ifndef ENABLE_CARD_aim104
+#define ENABLE_CARD_aim104 0
 #endif
-#ifndef CC104
-#define CC104 0
+#ifndef ENABLE_CARD_pc_i03
+#define ENABLE_CARD_pc_i03 0
 #endif
-#ifndef AIM104
-#define AIM104 0
+#ifndef ENABLE_CARD_pcm3680
+#define ENABLE_CARD_pcm3680 0
 #endif
-#ifndef PCI03
-#define PCI03 0
+#ifndef ENABLE_CARD_m437
+#define ENABLE_CARD_m437 0
 #endif
-#ifndef PCM3680
-#define PCM3680 0
+#ifndef ENABLE_CARD_pcccan
+#define ENABLE_CARD_pcccan 0
 #endif
-#ifndef M437
-#define M437 0
+#ifndef ENABLE_CARD_ssv
+#define ENABLE_CARD_ssv 0
 #endif
-#ifndef PCCCAN
-#define PCCCAN 0
+#ifndef ENABLE_CARD_bfadcan
+#define ENABLE_CARD_bfadcan 0
 #endif
-#ifndef SSV
-#define SSV 0
+#ifndef ENABLE_CARD_pikronisa
+#define ENABLE_CARD_pikronisa 0
 #endif
-#ifndef TEMPLATE
-#define TEMPLATE 0
+#ifndef ENABLE_CARD_template
+#define ENABLE_CARD_template 0
 #endif
 
 #include <linux/string.h>
@@ -70,37 +77,41 @@ int parse_mod_parms(void)
        }
 
        while ( (hw[i] != NULL) && (i < MAX_HW_CARDS) ) {
-               if ( !strcmp(hw[i],"pip5") && PIP )
+               if ( !strcmp(hw[i],"pip5") && ENABLE_CARD_pip )
                        irq_needed++;
-               else if (!strcmp(hw[i],"pip6") && PIP)
+               else if (!strcmp(hw[i],"pip6") && ENABLE_CARD_pip)
                        irq_needed++;
-               else if (!strcmp(hw[i],"smartcan") && SMARTCAN)
+               else if (!strcmp(hw[i],"smartcan") && ENABLE_CARD_smartcan)
                        irq_needed++;
-               else if (!strcmp(hw[i],"pccan-q") && PCCAN)
+               else if (!strcmp(hw[i],"pccan-q") && ENABLE_CARD_pccan)
                        irq_needed=irq_needed+4;
-               else if (!strcmp(hw[i],"pccan-f") && PCCAN)
+               else if (!strcmp(hw[i],"pccan-f") && ENABLE_CARD_pccan)
                        irq_needed++;
-               else if (!strcmp(hw[i],"pccan-s") && PCCAN)
+               else if (!strcmp(hw[i],"pccan-s") && ENABLE_CARD_pccan)
                        irq_needed++;
-               else if (!strcmp(hw[i],"pccan-d") && PCCAN)
+               else if (!strcmp(hw[i],"pccan-d") && ENABLE_CARD_pccan)
                        irq_needed=irq_needed+2;
-               else if (!strcmp(hw[i],"nsican") && NSI)
+               else if (!strcmp(hw[i],"nsican") && ENABLE_CARD_nsi)
                        irq_needed++;
-               else if (!strcmp(hw[i],"cc104") && CC104)
+               else if (!strcmp(hw[i],"cc104") && ENABLE_CARD_cc_can104)
                        irq_needed++;
-               else if (!strcmp(hw[i],"aim104") && AIM104)
+               else if (!strcmp(hw[i],"aim104") && ENABLE_CARD_aim104)
                        irq_needed++;
-               else if (!strcmp(hw[i],"pc-i03") && PCI03)
+               else if (!strcmp(hw[i],"pc-i03") && ENABLE_CARD_pc_i03)
                        irq_needed++;
-               else if (!strcmp(hw[i],"pcm3680") && PCM3680)
+               else if (!strcmp(hw[i],"pcm3680") && ENABLE_CARD_pcm3680)
                        irq_needed=irq_needed+2;
-               else if (!strcmp(hw[i],"m437") && M437)
+               else if (!strcmp(hw[i],"m437") && ENABLE_CARD_m437)
                        irq_needed++;
-               else if (!strcmp(hw[i],"pcccan") && PCCCAN)
+               else if (!strcmp(hw[i],"pcccan") && ENABLE_CARD_pcccan)
                        irq_needed++;
-               else if (!strcmp(hw[i],"ssv") && SSV)
+               else if (!strcmp(hw[i],"ssv") && ENABLE_CARD_ssv)
                        irq_needed=irq_needed+2;
-               else if (!strcmp(hw[i],"template") && TEMPLATE);
+               else if (!strcmp(hw[i],"bfadcan") && ENABLE_CARD_bfadcan)
+                       irq_needed++;
+               else if (!strcmp(hw[i],"pikronisa") && ENABLE_CARD_pikronisa)
+                       irq_needed++;
+               else if (!strcmp(hw[i],"template") && ENABLE_CARD_template);
                else {
                        CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",hw[i]);
                        return -EINVAL;
@@ -122,7 +133,7 @@ int parse_mod_parms(void)
        while ( (irq[irq_supplied] != -1) & (irq_supplied<MAX_IRQ) )
                irq_supplied++;
        while ( (hw[j] != NULL) && (j<MAX_HW_CARDS) ) {
-               if (!strcmp(hw[j],"template") && TEMPLATE)
+               if (!strcmp(hw[j],"template") && ENABLE_CARD_template)
                        irq_needed = irq_supplied;
                j++;
        }
index 862a297..f9ff108 100644 (file)
 #endif
 
 #include <linux/fs.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 #include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
 #include <linux/version.h>
 
 #include "../include/main.h"
@@ -78,7 +83,7 @@ int can_open(struct inode *inode, struct file *file)
        fifo->rx_size = MAX_BUF_LENGTH * sizeof(struct canmsg_t);
        fifo->tx_size = fifo->rx_size;
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
        init_waitqueue(&fifo->readq);
        init_waitqueue(&fifo->writeq);
 #else
@@ -89,12 +94,13 @@ int can_open(struct inode *inode, struct file *file)
        fifo->rx_in_progress = 0;
        fifo->tx_in_progress = 0;
 
-       fifo->head = fifo->tail = 0; //TEMP!!
+       chip->flags |= BUFFERS_ALLOCATED;
 
        if (chip->chipspecops->pre_read_config(chip,obj)<0)
                CANMSG("Error initializing chip for receiving\n");
                
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50))
        MOD_INC_USE_COUNT;
-       
+#endif 
        return 0;
 }
diff --git a/lincan/src/pc_i03.c b/lincan/src/pc_i03.c
new file mode 100644 (file)
index 0000000..bf64ff6
--- /dev/null
@@ -0,0 +1,300 @@
+/* pc-i03.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wnadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7  6 Aug 2001
+ */ 
+
+#include <linux/autoconf.h>
+#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined (MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include "../include/main.h"
+#include "../include/pc-i03.h"
+#include "../include/sja1000.h"
+
+/* Basic hardware io address. This is also stored in the hardware structure but
+ * we need it global, else we have to change many internal functions.
+ * pc-i03_base_addr is initialized in pc-i03_init_chip_data().
+ */
+unsigned int pci03_base_addr; 
+
+/*
+ * IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ */
+#define IO_RANGE 0x200 // The pc-i03 uses an additional 0x100 bytes reset space
+
+/**
+ * pci03_request_io: - reserve io memory
+ * @io_addr: The reserved memory starts at @io_addr, wich is the module 
+ * parameter @io.
+ *
+ * The function pci03_request_io() is used to reserve the io-memory. If your
+ * hardware uses a dedicated memory range as hardware control registers you
+ * will have to add the code to reserve this memory as well. 
+ * %IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/pc-i03.c
+ */
+int pci03_request_io(unsigned long io_addr)
+{
+       if (check_region(io_addr,IO_RANGE)) {
+               CANMSG("Unable to open port: 0x%lx\n",io_addr);
+               return -ENODEV;
+       }
+       else {
+               request_region(io_addr,IO_RANGE,DEVICE_NAME);
+               DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1);
+       }
+       return 0;
+}
+
+/**
+ * pci03_release_io - free reserved io-memory
+ * @io_addr: Start of the memory range to be released.
+ *
+ * The function pci03_release_io() is used to free reserved io-memory.
+ * In case you have reserved more io memory, don't forget to free it here.
+ * IO_RANGE is the io-memory range that gets released, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function always returns zero
+ * File: src/pc-i03.c
+ */
+int pci03_release_io(unsigned long io_addr)
+{
+       release_region(io_addr,IO_RANGE);
+
+       return 0;
+}
+
+/**
+ * pci03_reset - hardware reset routine
+ * @card: Number of the hardware card.
+ *
+ * The function pci03_reset() is used to give a hardware reset. This is 
+ * rather hardware specific so I haven't included example code. Don't forget to 
+ * check the reset status of the chip before returning.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/pc-i03.c
+ */
+int pci03_reset(int card)
+{
+       int i=0;
+
+       DEBUGMSG("Resetting pc-i03 hardware ...\n");
+       pci03_write_register(0x01,pci03_base_addr +
+                               0x100); // Write arbitrary data to reset mem
+       udelay(20000);
+
+       pci03_write_register(0x00, pci03_base_addr + SJACR);
+                                                                       
+       /* Check hardware reset status */
+       i=0;
+       while ( (pci03_read_register(pci03_base_addr + SJACR) & CR_RR)
+                                                                && (i<=15) ) {
+               udelay(20000);
+               i++;
+       }
+       if (i>=15) {
+               CANMSG("Reset status timeout!\n");
+               CANMSG("Please check your hardware.\n");
+               return -ENODEV;
+       }
+       else
+               DEBUGMSG("Chip[0] reset status ok.\n");
+
+       return 0;
+}
+
+#define RESET_ADDR 0x100
+#define NR_82527 0
+#define NR_SJA1000 1
+
+/**
+ * pci03_init_hw_data - Initialze hardware cards
+ * @card: Number of the hardware card.
+ *
+ * The function pci03_init_hw_data() is used to initialize the hardware
+ * structure containing information about the installed CAN-board.
+ * %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 hardware uses programmable interrupts.
+ * Return Value: The function always returns zero
+ * File: src/pc-i03.c
+ */
+int pci03_init_hw_data(int card) 
+{
+       candevices_p[card]->res_addr=RESET_ADDR;
+       candevices_p[card]->nr_82527_chips=NR_82527;
+       candevices_p[card]->nr_sja1000_chips=NR_SJA1000;
+       candevices_p[card]->flags |= ~PROGRAMMABLE_IRQ;
+
+       return 0;
+}
+
+#define CHIP_TYPE "sja1000"
+/**
+ * pci03_init_chip_data - Initialize chips
+ * @card: Number of the hardware card
+ * @chipnr: Number of the CAN chip on the hardware card
+ *
+ * The function pci03_init_chip_data() is used to initialize the hardware
+ * structure containing information about the CAN chips.
+ * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
+ * "sja1000".
+ * The @chip_base_addr entry represents the start of the 'official' memory map
+ * of the installed chip. It's likely that this is the same as the @io_addr
+ * argument supplied at module loading time.
+ * The @clock entry holds the chip clock value in Hz.
+ * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
+ * register. Options defined in the %sja1000.h file:
+ * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN
+ * The entry @sja_ocr_reg holds hardware specific options for the Output Control
+ * register. Options defined in the %sja1000.h file:
+ * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK,
+ * %OCR_TX0_LH, %OCR_TX1_ZZ.
+ * The entry @int_clk_reg holds hardware specific options for the Clock Out
+ * register. Options defined in the %i82527.h file:
+ * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
+ * The entry @int_bus_reg holds hardware specific options for the Bus 
+ * Configuration register. Options defined in the %i82527.h file:
+ * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
+ * Return Value: The function always returns zero
+ * File: src/pc-i03.c
+ */
+int pci03_init_chip_data(int card, int chipnr)
+{
+       pci03_base_addr = candevices_p[card]->io_addr;
+       candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE;
+       candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr;
+       candevices_p[card]->chip[chipnr]->clock = 16000000;
+       candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF;
+       candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | 
+                                                       OCR_TX0_HL | OCR_TX1_LZ;
+
+       return 0;
+}
+
+/**
+ * pci03_init_obj_data - Initialize message buffers
+ * @chipnr: Number of the CAN chip
+ * @objnr: Number of the message buffer
+ *
+ * The function pci03_init_obj_data() is used to initialize the hardware
+ * structure containing information about the different message objects on the
+ * CAN chip. In case of the sja1000 there's only one message object but on the
+ * i82527 chip there are 15.
+ * The code below is for a i82527 chip and initializes the object base addresses
+ * The entry @obj_base_addr represents the first memory address of the message 
+ * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
+ * base address.
+ * Unless the hardware uses a segmented memory map, flags can be set zero.
+ * Return Value: The function always returns zero
+ * File: src/pc-i03.c
+ */
+int pci03_init_obj_data(int chipnr, int objnr)
+{
+       chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr;
+       chips_p[chipnr]->msgobj[objnr]->flags=0;
+       
+       return 0;
+}
+
+/**
+ * pci03_program_irq - program interrupts
+ * @card: Number of the hardware card.
+ *
+ * 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 
+ * 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
+ * File: src/pc-i03.c
+ */
+int pci03_program_irq(int card)
+{
+       return 0;
+}
+
+/**
+ * pci03_write_register - Low level write register routine
+ * @data: data to be written
+ * @address: memory address to write to
+ *
+ * The function pci03_write_register() is used to write to hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific write process.
+ * Return Value: The function does not return a value
+ * File: src/pc-i03.c
+ */
+void pci03_write_register(unsigned char data, unsigned long address)
+{
+       unsigned int *pci03_base_ptr;
+       unsigned short address_to_write;
+
+       /* The read/write functions are called by an extra abstract function.
+        * This extra function adds the basic io address of the card to the
+        * memory address we want to write to, so we substract the basic io
+        * address again to obtain the offset into the hardware's memory map.
+        */
+       address_to_write = address - pci03_base_addr; // Offset
+       pci03_base_ptr = (unsigned int *)(pci03_base_addr * 0x100001);
+       (*(pci03_base_ptr+address_to_write)) = data;
+}
+
+/**
+ * pci03_read_register - Low level read register routine
+ * @address: memory address to read from
+ *
+ * The function pci03_read_register() is used to read from hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific read process.
+ * Return Value: The function returns the value stored in @address
+ * File: src/pc-i03.c
+ */
+unsigned pci03_read_register(unsigned long address)
+{
+       unsigned int *pci03_base_ptr;
+       unsigned short address_to_read;
+
+       /* The read/write functions are called by an extra abstract function.
+        * This extra function adds the basic io address of the card to the
+        * memory address we want to write to, so we substract the basic io
+        * address again to obtain the offset into the hardware's memory map.
+        */
+       address_to_read = address - pci03_base_addr;
+       pci03_base_ptr = (unsigned int *)(pci03_base_addr * 0x100001);
+       return (*(pci03_base_ptr+address_to_read));
+}
+
+int pci03_register(struct hwspecops_t *hwspecops)
+{
+       hwspecops->request_io = pci03_request_io;
+       hwspecops->release_io = pci03_release_io;
+       hwspecops->reset = pci03_reset;
+       hwspecops->init_hw_data = pci03_init_hw_data;
+       hwspecops->init_chip_data = pci03_init_chip_data;
+       hwspecops->init_obj_data = pci03_init_obj_data;
+       hwspecops->write_register = pci03_write_register;
+       hwspecops->read_register = pci03_read_register;
+       hwspecops->program_irq = pci03_program_irq;
+       return 0;
+}
index cfb816a..853986a 100644 (file)
 #include "../include/i82527.h"
 #include "../include/sja1000p.h"
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) /* may need correction */
+       #ifndef request_mem_region
+               #define request_mem_region(start,size,dev) (1)
+               #define release_mem_region(start,size) 
+       #endif /*request_mem_region*/
+#endif /* 2.4.0 */
+
 /* Basic hardware io address. This is also stored in the hardware structure but
  * we need it global, else we have to change many internal functions.
  * pcm3680_base_addr is initialized in pcm3680_init_chip_data().
  */
-unsigned int pcm3680_base_addr;
+unsigned long pcm3680_base_addr;
+static unsigned long isa_base = 0L; 
 
 /*
  * IO_RANGE is the io-memory range that gets reserved, please adjust according
  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
  */
-#define IO_RANGE 0x200
+#define IO_RANGE 0x400
 
 /**
  * template_request_io: - reserve io memory
@@ -53,14 +61,20 @@ unsigned int pcm3680_base_addr;
  */
 int pcm3680_request_io(unsigned long io_addr)
 {
-       if (check_region(io_addr,IO_RANGE)) {
-               CANMSG("Unable to open port: 0x%lx\n",io_addr);
+        unsigned long remap_addr;
+       if (!request_mem_region(io_addr,IO_RANGE,DEVICE_NAME " - pcm3680")) {
+               CANMSG("Unable to request IO-memory: 0x%lx\n",io_addr);
                return -ENODEV;
        }
-       else {
-               request_region(io_addr,IO_RANGE,DEVICE_NAME);
-               DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1);
+       if ( !( remap_addr = (long) ioremap( io_addr, IO_RANGE ) ) ) {
+               CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr);
+               release_mem_region(io_addr,IO_RANGE);
+               return -ENODEV;
+       
        }
+       isa_base=remap_addr-io_addr;
+
+       DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1);
        return 0;
 }
 
@@ -78,8 +92,8 @@ int pcm3680_request_io(unsigned long io_addr)
  */
 int pcm3680_release_io(unsigned long io_addr)
 {
-       release_region(io_addr,IO_RANGE);
-
+       iounmap((void*)isa_base);
+       release_mem_region(io_addr,IO_RANGE);
        return 0;
 }
 
@@ -95,54 +109,36 @@ int pcm3680_release_io(unsigned long io_addr)
  */
 int pcm3680_reset(int card)
 {
-//     int i=0;
-
-//     DEBUGMSG("Resetting pcm3680 hardware ...\n");
-//     pcm3680_write_register(0x01, candevices_p[card]->io_addr +
-//                             0x100); // Write arbitrary data to reset mem
-//     pcm3680_write_register(0x01, candevices_p[card]->io_addr +
-//                             0x300); // Write arbitrary data to reset mem
-//     udelay(20000);
-
-//     pcm3680_write_register(0x00, candevices_p[card]->io_addr + SJACR);
-//     pcm3680_write_register(0x00, candevices_p[card]->io_addr + SJACR+0x200);
-                                                                       
-       /* Check hardware reset status chip 0 */
-/*     i=0;
-       while ( (pcm3680_read_register(candevices_p[card]->io_addr + SJACR) 
-                                                       & CR_RR) && (i<=15) ) {
-               udelay(20000);
-               i++;
-       }
-       if (i>=15) {
-               CANMSG("Reset status timeout!\n");
-               CANMSG("Please check your hardware.\n");
-               return -ENODEV;
-       }
-       else
-               DEBUGMSG("Chip[0] reset status ok.\n");
-*/
-       /* Check hardware reset status chip 1 */
-/*     i=0;
-       while ( (pcm3680_read_register( candevices_p[card]->io_addr + SJACR + 
-                                               0x200) & CR_RR) && (i<=15) ) {
-               udelay(20000);
-               i++;
-       }
-       if (i>=15) {
-               CANMSG("Reset status timeout!\n");
-               CANMSG("Please check your hardware.\n");
-               return -ENODEV;
+       int i=0;
+       struct chip_t *chip;
+       int chipnr;
+       
+       DEBUGMSG("Resetting pcm3680 hardware ...\n");
+       for(chipnr=0;chipnr<candevices_p[card]->nr_sja1000_chips;chipnr++) {
+               chip=candevices_p[card]->chip[chipnr];
+               pcm3680_write_register(MOD_RM, chip->chip_base_addr+SJAMOD);
+               udelay(1000);
+               pcm3680_write_register(0x00, chip->chip_base_addr + SJAIER);
+               /* Write arbitrary data to reset chip */
+               pcm3680_write_register(0x01, chip->chip_base_addr + 0x100);
+               udelay(1000);
+               i=20;
+               while (pcm3680_read_register(chip->chip_base_addr+SJAMOD)&MOD_RM){
+                       if(!i--) return -ENODEV;
+                       udelay(1000);
+                       pcm3680_write_register(0, chip->chip_base_addr+SJAMOD);
+               }
+               udelay(1000);
+               pcm3680_write_register(CDR_PELICAN, chip->chip_base_addr+SJACDR);
+               pcm3680_write_register(0x00, chip->chip_base_addr + SJAIER);
        }
-       else
-               DEBUGMSG("Chip[1] reset status ok.\n");
-*/
+
        return 0;
 }
 
 #define RESET_ADDR 0x100
 #define NR_82527 0
-#define NR_SJA1000 1
+#define NR_SJA1000 2
 
 /**
  * template_init_hw_data - Initialze hardware cards
@@ -202,7 +198,8 @@ int pcm3680_init_chip_data(int card, int chipnr)
 {
        pcm3680_base_addr = candevices_p[card]->io_addr;
        candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE;
-       candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr;
+       candevices_p[card]->chip[chipnr]->chip_base_addr=
+                       candevices_p[card]->io_addr + 0x200*chipnr;
        candevices_p[card]->chip[chipnr]->clock = 16000000;
        candevices_p[card]->chip[chipnr]->int_clk_reg = 0x0;
        candevices_p[card]->chip[chipnr]->int_bus_reg = 0x0;
@@ -268,7 +265,7 @@ int pcm3680_program_irq(int card)
  */
 void pcm3680_write_register(unsigned char data, unsigned long address)
 {
-       writeb(data,address);
+       writeb(data,isa_base+address);
 }
 
 /**
@@ -283,7 +280,7 @@ void pcm3680_write_register(unsigned char data, unsigned long address)
  */
 unsigned pcm3680_read_register(unsigned long address)
 {
-       return readb(address);
+       return readb(isa_base+address);
 }
 
 /* !!! Don't change this function !!! */
diff --git a/lincan/src/pikronisa.c b/lincan/src/pikronisa.c
new file mode 100644 (file)
index 0000000..104cbbc
--- /dev/null
@@ -0,0 +1,288 @@
+/* pikronisa.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7  6 Aug 2001
+ */ 
+
+#include <linux/autoconf.h>
+#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined (MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include "../include/main.h"
+#include "../include/pikronisa.h"
+#include "../include/i82527.h"
+#include "../include/sja1000p.h"
+
+/*
+ * IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ */
+#define IO_RANGE 0x100
+
+static long base = 0L; 
+
+/**
+ * pikronisa_request_io: - reserve io memory
+ * @io_addr: The reserved memory starts at @io_addr, wich is the module 
+ * parameter @io.
+ *
+ * The function pikronisa_request_io() is used to reserve the io-memory. If your
+ * hardware uses a dedicated memory range as hardware control registers you
+ * will have to add the code to reserve this memory as well. 
+ * %IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/pikronisa.c
+ */
+int pikronisa_request_io(unsigned long io_addr)
+{
+        int remap_addr;
+       if ( !( remap_addr = (long) ioremap( io_addr, IO_RANGE ) ) ) {
+               CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr);
+               return -ENODEV;
+       
+       }
+       base=remap_addr-io_addr;
+       DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1);
+       return 0;
+}
+
+/**
+ * pikronisa_release_io - free reserved io-memory
+ * @io_addr: Start of the memory range to be released.
+ *
+ * The function pikronisa_release_io() is used to free reserved io-memory.
+ * In case you have reserved more io memory, don't forget to free it here.
+ * IO_RANGE is the io-memory range that gets released, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function always returns zero
+ * File: src/pikronisa.c
+ */
+int pikronisa_release_io(unsigned long io_addr)
+{
+       /* release I/O memory mapping */
+       iounmap((void*)base);
+
+       return 0;
+}
+
+/**
+ * pikronisa_reset - hardware reset routine
+ * @card: Number of the hardware card.
+ *
+ * The function pikronisa_reset() is used to give a hardware reset. This is 
+ * rather hardware specific so I haven't included example code. Don't forget to 
+ * check the reset status of the chip before returning.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/pikronisa.c
+ */
+int pikronisa_reset(int card)
+{
+       int i;
+       struct chip_t *chip=candevices_p[card]->chip[0];
+       unsigned cdr;
+       
+       pikronisa_write_register(MOD_RM, chip->chip_base_addr+SJAMOD);
+       udelay(1000);
+       
+       cdr=pikronisa_read_register(chip->chip_base_addr+SJACDR);
+       pikronisa_write_register(cdr|CDR_PELICAN, chip->chip_base_addr+SJACDR);
+
+       pikronisa_write_register(0, chip->chip_base_addr+SJAIER);
+
+       i=20;
+       pikronisa_write_register(0, chip->chip_base_addr+SJAMOD);
+       while (pikronisa_read_register(chip->chip_base_addr+SJAMOD)&MOD_RM){
+               if(!i--) return -ENODEV;
+               udelay(1000);
+               pikronisa_write_register(0, chip->chip_base_addr+SJAMOD);
+       }
+
+       cdr=pikronisa_read_register(chip->chip_base_addr+SJACDR);
+       pikronisa_write_register(cdr|CDR_PELICAN, chip->chip_base_addr+SJACDR);
+
+       pikronisa_write_register(0, chip->chip_base_addr+SJAIER);
+       
+       return 0;
+}
+
+#define RESET_ADDR 0x0
+#define NR_82527 0
+#define NR_SJA1000 1
+
+/**
+ * pikronisa_init_hw_data - Initialze hardware cards
+ * @card: Number of the hardware card.
+ *
+ * The function pikronisa_init_hw_data() is used to initialize the hardware
+ * structure containing information about the installed CAN-board.
+ * %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 hardware uses programmable interrupts.
+ * Return Value: The function always returns zero
+ * File: src/pikronisa.c
+ */
+int pikronisa_init_hw_data(int card) 
+{
+       candevices_p[card]->res_addr=RESET_ADDR;
+       candevices_p[card]->nr_82527_chips=0;
+       candevices_p[card]->nr_sja1000_chips=1;
+       candevices_p[card]->flags |= PROGRAMMABLE_IRQ*0;
+
+       return 0;
+}
+
+#define CHIP_TYPE "sja1000p"
+/* #define CHIP_TYPE "sja1000" */
+
+/**
+ * pikronisa_init_chip_data - Initialize chips
+ * @card: Number of the hardware card
+ * @chipnr: Number of the CAN chip on the hardware card
+ *
+ * The function pikronisa_init_chip_data() is used to initialize the hardware
+ * structure containing information about the CAN chips.
+ * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
+ * "sja1000".
+ * The @chip_base_addr entry represents the start of the 'official' memory map
+ * of the installed chip. It's likely that this is the same as the @io_addr
+ * argument supplied at module loading time.
+ * The @clock entry holds the chip clock value in Hz.
+ * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
+ * register. Options defined in the %sja1000.h file:
+ * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN
+ * The entry @sja_ocr_reg holds hardware specific options for the Output Control
+ * register. Options defined in the %sja1000.h file:
+ * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK,
+ * %OCR_TX0_LH, %OCR_TX1_ZZ.
+ * The entry @int_clk_reg holds hardware specific options for the Clock Out
+ * register. Options defined in the %i82527.h file:
+ * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
+ * The entry @int_bus_reg holds hardware specific options for the Bus 
+ * Configuration register. Options defined in the %i82527.h file:
+ * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
+ * The entry @int_cpu_reg holds hardware specific options for the cpu interface
+ * register. Options defined in the %i82527.h file:
+ * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST.
+ * Return Value: The function always returns zero
+ * File: src/pikronisa.c
+ */
+int pikronisa_init_chip_data(int card, int chipnr)
+{
+       /* pikronisa_base_addr = candevices_p[card]->io_addr; */
+       candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE;
+       candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr;
+       candevices_p[card]->chip[chipnr]->clock = 24000000;
+       candevices_p[card]->chip[chipnr]->int_clk_reg = 0x0;
+       candevices_p[card]->chip[chipnr]->int_bus_reg = 0x0;
+       candevices_p[card]->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF;
+       candevices_p[card]->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL |
+                                                               OCR_TX0_LH;
+
+       return 0;
+}
+
+/**
+ * pikronisa_init_obj_data - Initialize message buffers
+ * @chipnr: Number of the CAN chip
+ * @objnr: Number of the message buffer
+ *
+ * The function pikronisa_init_obj_data() is used to initialize the hardware
+ * structure containing information about the different message objects on the
+ * CAN chip. In case of the sja1000 there's only one message object but on the
+ * i82527 chip there are 15.
+ * The code below is for a i82527 chip and initializes the object base addresses
+ * The entry @obj_base_addr represents the first memory address of the message 
+ * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
+ * base address.
+ * Unless the hardware uses a segmented memory map, flags can be set zero.
+ * Return Value: The function always returns zero
+ * File: src/pikronisa.c
+ */
+int pikronisa_init_obj_data(int chipnr, int objnr)
+{
+       chips_p[chipnr]->msgobj[objnr]->obj_base_addr=chips_p[chipnr]->chip_base_addr;
+       chips_p[chipnr]->msgobj[objnr]->flags=0;
+       return 0;
+}
+
+/**
+ * pikronisa_program_irq - program interrupts
+ * @card: Number of the hardware card.
+ *
+ * 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 
+ * 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
+ * File: src/pikronisa.c
+ */
+int pikronisa_program_irq(int card)
+{
+       return 0;
+}
+
+/**
+ * pikronisa_write_register - Low level write register routine
+ * @data: data to be written
+ * @address: memory address to write to
+ *
+ * The function pikronisa_write_register() is used to write to hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific write process.
+ * Return Value: The function does not return a value
+ * File: src/pikronisa.c
+ */
+void pikronisa_write_register(unsigned char data, unsigned long address)
+{
+       /*DEBUGMSG("pikronisa_write_register: base=0x%lx addr=0x%lx data=0x%x",
+               base,address,data);*/
+       writeb(data,base+address);
+}
+
+/**
+ * pikronisa_read_register - Low level read register routine
+ * @address: memory address to read from
+ *
+ * The function pikronisa_read_register() is used to read from hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific read process.
+ * Return Value: The function returns the value stored in @address
+ * File: src/pikronisa.c
+ */
+unsigned pikronisa_read_register(unsigned long address)
+{
+       return readb(base+address);
+}
+
+/* !!! Don't change this function !!! */
+int pikronisa_register(struct hwspecops_t *hwspecops)
+{
+       hwspecops->request_io = pikronisa_request_io;
+       hwspecops->release_io = pikronisa_release_io;
+       hwspecops->reset = pikronisa_reset;
+       hwspecops->init_hw_data = pikronisa_init_hw_data;
+       hwspecops->init_chip_data = pikronisa_init_chip_data;
+       hwspecops->init_obj_data = pikronisa_init_obj_data;
+       hwspecops->write_register = pikronisa_write_register;
+       hwspecops->read_register = pikronisa_read_register;
+       hwspecops->program_irq = pikronisa_program_irq;
+       return 0;
+}
index 09f0ae4..6bbfd8d 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/string.h>
 #include <asm/errno.h>
 #include <asm/io.h>
 
index 401148e..79309e0 100644 (file)
 #include <linux/modversions.h>
 #endif
 
+#include <linux/version.h>
 #include <linux/kernel.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 #include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
 #include <linux/proc_fs.h>
 #include <linux/version.h>
 
@@ -31,7 +36,7 @@ int remove_channel_from_procdir(void);
 int add_object_to_procdir(void);
 int remove_object_from_procdir(void);
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 static int candev_readlink(struct proc_dir_entry *de, char *page);
 #endif
 
@@ -45,7 +50,7 @@ struct canproc_t *base=&can_proc_base;
 /* The following functions are needed only for kernel version 2.2. Kernel
  * version 2.4 already defines them for us.
  */
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 static void can_fill_inode(struct inode *inode, int fill)
 {
        if (fill)
@@ -96,7 +101,7 @@ int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *par
  */
 int can_init_procdir(void)
 {
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
        base->can_proc_entry = new_can_proc_entry(0, "can", S_IFDIR | S_IRUGO | 
                                        S_IXUGO, 0, &proc_root);
 #else
@@ -118,7 +123,7 @@ int can_delete_procdir(void)
 {
        if (remove_channel_from_procdir()) 
                return -ENODEV;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
        if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
                return -ENODEV;
 #else
@@ -144,7 +149,7 @@ int add_channel_to_procdir(void)
 
                sprintf(base->channel[cc]->ch_name, "channel%d",cc);
                                                
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
                base->channel[cc]->ch_entry = new_can_proc_entry(0, 
                                                base->channel[cc]->ch_name,
                                                S_IFDIR | S_IRUGO | S_IXUGO, 0, 
@@ -171,7 +176,7 @@ int remove_channel_from_procdir(void)
        
        while (cc != 0) {
                cc--;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
                if (can_remove_proc_entry(base->channel[cc]->ch_entry,
                                                        base->can_proc_entry))
                        return -ENODEV;
@@ -210,7 +215,7 @@ int add_object_to_procdir(void)
                sprintf(base->channel[cc]->object[i]->obj_name,"object%d",i);
                sprintf(base->channel[cc]->object[i]->lnk_name,"dev");
                                                                
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
                base->channel[cc]->object[i]->obj_entry=new_can_proc_entry(
                                0, base->channel[cc]->object[i]->obj_name,
                                S_IFDIR | S_IRUGO | S_IXUGO, 0, 
@@ -258,7 +263,7 @@ int remove_object_from_procdir(void)
                obj=1;
 
        for (i=0; i<obj; i++) {
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
                if (can_remove_proc_entry( base->channel[cc]->object[i]->lnk,
                                base->channel[cc]->object[i]->obj_entry))       
                        return -ENODEV;
@@ -277,7 +282,7 @@ int remove_object_from_procdir(void)
        return 0;
 }
 
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
 static int candev_readlink(struct proc_dir_entry *de, char *page)
 {
        int i=0, nchip=0, nobj=0;
index 4e02801..1111401 100644 (file)
@@ -5,6 +5,9 @@
  * Version 0.7  6 Aug 2001
  */
 
+#define __NO_VERSION__
+#include <linux/module.h> 
+
 #include <linux/autoconf.h>
 #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
 #define MODVERSIONS
 #include <linux/modversions.h>
 #endif
 
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 #include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
 #include <linux/version.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
@@ -45,8 +53,8 @@ inline ssize_t can_std_read(struct file *file, struct canfifo_t *fifo,
                        return -EINTR;
                }
                if (!can_timeout) {
-                       DEBUGMSG("Rx timeout\n");
-                       return -EIO;
+                       DEBUGMSG("no data received\n");
+                       return 0;
                }
                if (obj->ret < 0)
                        return obj->ret;
@@ -62,14 +70,24 @@ inline ssize_t can_std_read(struct file *file, struct canfifo_t *fifo,
        bytes_to_copy = (length < bytes_avail) ? length : bytes_avail;
        ret = bytes_to_copy;
 
+       /* printk(KERN_CRIT "can RxFIFO b:%x e:%x bs:%x msg:%x rp:%x wp:%x btc:%x\n",
+              fifo->buf_rx_entry, fifo->buf_rx_entry+MAX_BUF_LENGTH,
+              fifo->rx_size, sizeof(struct canmsg_t),
+              fifo->rx_readp, fifo->rx_writep, bytes_to_copy); */
+
+
        /* Copy the data to user space */
        while (bytes_to_copy > 0) {
+                      
+               
                copy_to_user(buffer, fifo->rx_readp, sizeof(struct canmsg_t));
                buffer += sizeof(struct canmsg_t);
                bytes_to_copy -= sizeof(struct canmsg_t);
                fifo->rx_readp++;
                if (fifo->rx_readp >= fifo->buf_rx_entry + MAX_BUF_LENGTH)
                        fifo->rx_readp = fifo->buf_rx_entry;
+
+               /* printk(KERN_CRIT "can RxFIFO rp%x\n",fifo->rx_readp); */
        }
 
        return ret;
@@ -101,7 +119,7 @@ inline ssize_t can_rtr_read(struct chip_t *chip, struct msgobj_t *obj,
                new_rtr_entry=(struct rtr_id *)kmalloc(sizeof(struct rtr_id),GFP_ATOMIC);
                rtr_current->next=new_rtr_entry;
        }
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0))
        init_waitqueue(&new_rtr_entry->rtr_wq);
 #else
        init_waitqueue_head(&new_rtr_entry->rtr_wq);
diff --git a/lincan/src/select.c b/lincan/src/select.c
new file mode 100644 (file)
index 0000000..27b2d22
--- /dev/null
@@ -0,0 +1,56 @@
+/* select.c
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7.1-pi2  15 Nov 2002
+ * 
+ * added by Pavel Pisa pisa@cmp.felk.cvut.cz
+ */
+
+#include <linux/autoconf.h>
+#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined (MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/version.h>
+#include <linux/poll.h>
+
+#include "../include/main.h"
+#include "../include/select.h"
+
+unsigned int can_poll(struct file *file, poll_table *wait)
+{
+        unsigned int mask = 0;
+       struct msgobj_t *obj;
+       struct canfifo_t *fifo;
+
+       /* Initialize hardware pointers */
+       if ( (obj = objects_p[MINOR_NR]) == NULL) {
+               CANMSG("Could not assign buffer structure\n");
+               return 0;
+       }
+       if ( (fifo = obj->fifo) == NULL) {
+               CANMSG("Could not assign buffer memory.\n");
+               return 0;
+       }
+
+        if (file->f_mode & FMODE_WRITE) {
+                poll_wait(file, &fifo->writeq, wait);
+        }
+        if (file->f_mode & FMODE_READ) {
+                poll_wait(file, &fifo->readq, wait);
+        }
+        if ((file->f_mode & FMODE_READ)&&
+           (fifo->rx_readp != fifo->rx_writep)) {
+                 mask |= POLLIN | POLLRDNORM;
+        }
+        if ((file->f_mode & FMODE_WRITE)&&
+           (fifo->tx_readp == fifo->tx_writep)) {
+                 mask |= POLLOUT | POLLWRNORM;
+       }
+       return mask;
+}
index 74ba10f..a8f76cc 100644 (file)
@@ -5,6 +5,9 @@
  * Version 0.7  6 Aug 2001
  */ 
 
+#define __NO_VERSION__
+#include <linux/module.h>
+
 #include <linux/autoconf.h>
 #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
 #define MODVERSIONS
 #include <linux/modversions.h>
 #endif
 
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 #include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
 #include <linux/fs.h>
 
-#include "../.support"
+#include ".supported_cards.h"
 
 #include "../include/main.h"
 #include "../include/setup.h"
@@ -49,6 +57,8 @@ extern int pcm3680_register(struct hwspecops_t *hwspecops);
 extern int aim104_register(struct hwspecops_t *hwspecops);
 extern int pcccan_register(struct hwspecops_t *hwspecops);
 extern int ssv_register(struct hwspecops_t *hwspecops);
+extern int bfadcan_register(struct hwspecops_t *hwspecops);
+extern int pikronisa_register(struct hwspecops_t *hwspecops);
 
 int init_device_struct(int card);
 int init_hwspecops(int card);
@@ -86,7 +96,12 @@ int del_mem_from_list(void *address_p)
        DEBUGMSG("del_mem_from_list %p, mem_head=%p\n", address_p, mem_head);
        return 0;
 #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) {
@@ -114,6 +129,10 @@ int del_mem_list(void)
        DEBUGMSG("del_mem_list, mem_head=%p\n", mem_head);
        return 0;
 #endif
+       if(mem_head == NULL) {
+               CANMSG("del_mem_list: mem_head == NULL!\n");
+               return 0;
+       }
 
        while (mem_head->next != NULL) {
                mem_old=mem_head;
@@ -271,12 +290,12 @@ int init_obj_struct(int card, int chip)
 
 int init_hwspecops(int card)
 {
-       #ifdef TEMPLATE
+       #ifdef ENABLE_CARD_template
        if (!strcmp(candevices_p[card]->hwname,"template")) {
                template_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef PIP
+       #ifdef ENABLE_CARD_pip
        if (!strcmp(candevices_p[card]->hwname,"pip5")) {
                pip5_register(candevices_p[card]->hwspecops);
        }
@@ -284,37 +303,37 @@ int init_hwspecops(int card)
                pip6_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef SMARTCAN
+       #ifdef ENABLE_CARD_smartcan
        if (!strcmp(candevices_p[card]->hwname,"smartcan")) {
                smartcan_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef NSI
+       #ifdef ENABLE_CARD_nsi
        if (!strcmp(candevices_p[card]->hwname,"nsican")) {
                nsi_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef CC104
+       #ifdef ENABLE_CARD_cc_can104
        if (!strcmp(candevices_p[card]->hwname,"cc104")) {
                cc104_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef AIM104
+       #ifdef ENABLE_CARD_aim104
        if (!strcmp(candevices_p[card]->hwname,"aim104")) {
                aim104_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef PCI03
+       #ifdef ENABLE_CARD_pc_i03
        if (!strcmp(candevices_p[card]->hwname,"pc-i03")) {
                pci03_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef PCM3680
+       #ifdef ENABLE_CARD_pcm3680
        if (!strcmp(candevices_p[card]->hwname,"pcm3680")) {
                pcm3680_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef PCCAN
+       #ifdef ENABLE_CARD_pccan
        if (!strcmp(candevices_p[card]->hwname,"pccan-f") |
                 !strcmp(candevices_p[card]->hwname,"pccan-s") ) {
                pccanf_register(candevices_p[card]->hwspecops);
@@ -326,21 +345,31 @@ int init_hwspecops(int card)
                pccanq_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef M437
+       #ifdef ENABLE_CARD_m437
        if (!strcmp(candevices_p[card]->hwname,"m437")) {
                m437_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef PCCCAN
+       #ifdef ENABLE_CARD_pcccan
        if (!strcmp(candevices_p[card]->hwname,"pcccan")) {
                pcccan_register(candevices_p[card]->hwspecops);
        }
        #endif
-       #ifdef SSV
+       #ifdef ENABLE_CARD_ssv
        if (!strcmp(candevices_p[card]->hwname,"ssv")) {
                ssv_register(candevices_p[card]->hwspecops);
        }
        #endif
+       #ifdef ENABLE_CARD_bfadcan
+       if (!strcmp(candevices_p[card]->hwname,"bfadcan")) {
+               bfadcan_register(candevices_p[card]->hwspecops);
+       }
+       #endif
+       #ifdef ENABLE_CARD_pikronisa
+       if (!strcmp(candevices_p[card]->hwname,"pikronisa")) {
+               pikronisa_register(candevices_p[card]->hwspecops);
+       }
+       #endif
        return 0;
 }
 
index e1da4c1..0955c76 100644 (file)
@@ -210,22 +210,22 @@ int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj)
 // TODO: this would be best sja1000_irq_read_handler(chip);
 // now just duplicate the code.
        do {
-               id=(can_read_reg(chip, SJARXID1)<<8) + can_read_reg(chip, 
-                                                       SJARXID0);
-               fifo->buf_rx_entry[fifo->head].length = (id>>8) & 0x0f;
-               fifo->buf_rx_entry[fifo->head].id = id>>5;
-               fifo->buf_rx_entry[fifo->head].flags = id&ID0_RTR ?
-                                                               MSG_RTR : 0;
-               fifo->buf_rx_entry[fifo->head].timestamp = 0;
-               fifo->buf_rx_entry[fifo->head].cob = 0;
-               for (i=0; i<fifo->buf_rx_entry[fifo->head].length; i++) {
-                       fifo->buf_rx_entry[fifo->head].data[i] = 
-                                       can_read_reg(chip,SJARXDAT0 + i);
-               }
-               fifo->head++;
-               if (fifo->head == MAX_BUF_LENGTH -1)
-                       fifo->head = 0;
+               id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8);
+               fifo->rx_writep->length = id & 0x0f;
+               fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0;
+               fifo->rx_writep->timestamp = 0;
+               fifo->rx_writep->cob = 0;
+               fifo->rx_writep->id = id>>5;
+
+               for (i=0; i<fifo->rx_writep->length; i++)
+                       fifo->rx_writep->data[i]=can_read_reg(chip, SJARXDAT0 + i);
+
+               fifo->rx_writep++;
+               if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH)
+                       fifo->rx_writep = fifo->buf_rx_entry;
+
                can_write_reg(chip, CMR_RRB, SJACMR);
+
        } while (can_read_reg(chip, SJASR) & SR_RBS);
 
 // enable interrupts
index f95f1a7..deb1c89 100644 (file)
 #include "../include/main.h"
 #include "../include/sja1000p.h"
 
-struct chip_t *chip_irq=NULL;
-struct candevice_t *device_irq=NULL;
-struct canfifo_t *fifo_irq=NULL;
-void (*put_reg)(unsigned char data, unsigned long address);
-unsigned (*get_reg)(unsigned long address);
-
-
-
 int sja1000p_enable_configuration(struct chip_t *chip)
 {
        int i=0;
@@ -41,8 +33,8 @@ int sja1000p_enable_configuration(struct chip_t *chip)
        flags=can_read_reg(chip,SJAMOD);
 
        while ((!(flags & MOD_RM)) && (i<=10)) {
-               can_write_reg(chip, MOD_RM, SJAMOD);
-// TODO: chinfigurable MOD_AFM (32/16 bit acceptance filter)
+               can_write_reg(chip, MOD_RM, SJAMOD);
+// TODO: configurable MOD_AFM (32/16 bit acceptance filter)
 // config MOD_LOM (listen only)
                udelay(100);
                i++;
@@ -64,9 +56,10 @@ int sja1000p_disable_configuration(struct chip_t *chip)
 
        flags=can_read_reg(chip,SJAMOD);
 
-       while ( (flags & MOD_RM) && (i<=10) ) {
+       while ( (flags & MOD_RM) && (i<=50) ) {
+// could be as long as 11*128 bit times after buss-off
                can_write_reg(chip, 0, SJAMOD);
-// TODO: chinfigurable MOD_AFM (32/16 bit acceptance filter)
+// TODO: configurable MOD_AFM (32/16 bit acceptance filter)
 // config MOD_LOM (listen only)
                udelay(100);
                i++;
@@ -203,39 +196,53 @@ void sja1000p_read(struct chip_t *chip, struct canfifo_t *fifo) {
        do {
                flags = can_read_reg(chip,SJAFRM);
                if(flags&FRM_FF) {
-                       fifo->buf_rx_entry[fifo->head].id =
+                       fifo->rx_writep->id =
                                (can_read_reg(chip,SJAID0)<<21) +
                                (can_read_reg(chip,SJAID1)<<13) +
                                (can_read_reg(chip,SJAID2)<<5) +
                                (can_read_reg(chip,SJAID3)>>3);
                        datastart = SJADATE;
                } else {
-                       fifo->buf_rx_entry[fifo->head].id =
+                       fifo->rx_writep->id =
                                (can_read_reg(chip,SJAID0)<<3) +
                                (can_read_reg(chip,SJAID1)>>5);
                        datastart = SJADATS;
                }
-               fifo->buf_rx_entry[fifo->head].flags =
+               fifo->rx_writep->flags =
                        ((flags & FRM_RTR) ? MSG_RTR : 0) |
                        ((flags & FRM_FF) ? MSG_EXT : 0);
                len = flags & FRM_DLC_M;
                for(i=0; i< len; i++) {
-                       fifo->buf_rx_entry[fifo->head].data[i]=
-                               can_read_reg(chip,datastart+i);
+                       fifo->rx_writep->data[i]=can_read_reg(chip,datastart+i);
                }
-               fifo->buf_rx_entry[fifo->head].length = len;
-               fifo->head++; fifo->head %= MAX_BUF_LENGTH;
-// FIXME: what if fifo->head == fifo->tail again ?
+               fifo->rx_writep->length = len;
+
+               fifo->rx_writep++;
+               if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH)
+                       fifo->rx_writep = fifo->buf_rx_entry;
+
+// FIXME: what if fifo->rx_writep == fifo->rx_readp again ?
+
                can_write_reg(chip, CMR_RRB, SJACMR);
        } while (can_read_reg(chip, SJASR) & SR_RBS);
 }
 
 int sja1000p_pre_read_config(struct chip_t *chip, struct msgobj_t *obj)
 {
-       int i;
-       i=can_read_reg(chip,SJASR);
+       int status;
+       status=can_read_reg(chip,SJASR);
        
-       if (!(i&SR_RBS)) {
+       if(status  & SR_BS) {
+               /* Try to recover from error condition */
+               DEBUGMSG("sja1000p_pre_read_config bus-off recover 0x%x\n",status);
+               sja1000p_enable_configuration(chip);
+               can_write_reg(chip, 0, SJARXERR);
+               can_write_reg(chip, 0, SJATXERR1);
+               can_read_reg(chip, SJAECC);
+               sja1000p_disable_configuration(chip);
+       }
+
+       if (!(status&SR_RBS)) {
                return 0;
        }
 
@@ -251,13 +258,23 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
 {
        int i=0; 
        unsigned int id;
+       int status;
 
        /* Wait until Transmit Buffer Status is released */
-       while ( !(can_read_reg(chip, SJASR) & SR_TBS) && 
+       while ( !((status=can_read_reg(chip, SJASR)) & SR_TBS) && 
                                                i++<MAX_TRANSMIT_WAIT_LOOPS) {
                udelay(i);
        }
        
+       if(status & SR_BS) {
+               /* Try to recover from error condition */
+               DEBUGMSG("sja1000p_pre_write_config bus-off recover 0x%x\n",status);
+               sja1000p_enable_configuration(chip);
+               can_write_reg(chip, 0, SJARXERR);
+               can_write_reg(chip, 0, SJATXERR1);
+               can_read_reg(chip, SJAECC);
+               sja1000p_disable_configuration(chip);
+       }
        if (!(can_read_reg(chip, SJASR) & SR_TBS)) {
                CANMSG("Transmit timed out, cancelling\n");
 // here we should check if there is no write/select waiting for this
@@ -292,9 +309,8 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
                        can_write_reg(chip, msg->data[i], SJADATE+i);
                }
        } else {
-               id=msg->id >> 5;
-               can_write_reg(chip, id & 0xff, SJAID0);
-               id >>= 8;
+               id=msg->id<<5;
+               can_write_reg(chip, (id >> 8) & 0xff, SJAID0);
                can_write_reg(chip, id & 0xff, SJAID1);
                for(i=0; i < msg->length; i++) {
                        can_write_reg(chip, msg->data[i], SJADATS+i);
@@ -379,47 +395,100 @@ int sja1000p_config_irqs(struct chip_t *chip, short irqs)
        return -ENOSYS;
 }
 
-void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+void sja1000p_irq_write_handler(struct chip_t *chip, struct canfifo_t *fifo)
 {
-       int irq_register;
-       chip_irq=(struct chip_t *)dev_id;
-       device_irq=(struct candevice_t *)chip_irq->hostdevice;
+       fifo->tx_readp++;
+       if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
+               fifo->tx_readp = fifo->buf_tx_entry;
+       if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty
+               fifo->tx_in_progress = 0;
+               if (waitqueue_active(&fifo->writeq)) {
+                       chip->msgobj[0]->ret = 0; //CHECKME or 26?
+                       wake_up_interruptible(&fifo->writeq);
+               }
+               return;
+       }
+       if (chip->chipspecops->pre_write_config(chip, chip->msgobj[0],
+                               fifo->tx_readp)) {
+               if (waitqueue_active(&fifo->writeq)) {
+                       chip->msgobj[0]->ret = -1;
+                       wake_up_interruptible(&fifo->writeq);
+                       return;
+               }
+       }
+       if (chip->chipspecops->send_msg(chip, chip->msgobj[0],
+               fifo->tx_readp)) {
+               if (waitqueue_active(&fifo->writeq)) {
+                       chip->msgobj[0]->ret = -1;
+                       wake_up_interruptible(&fifo->writeq);
+                       return;
+               }
+       }
 
-       put_reg=device_irq->hwspecops->write_register;
-       get_reg=device_irq->hwspecops->read_register;
+}
+
+#define MAX_RETR 10
 
-       irq_register=get_reg(chip_irq->chip_base_addr+SJAIR);
+void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int irq_register, status, error_code;
+       int static retransmitted=0; /* FIXME - should go into chip struct */
+       struct chip_t *chip=(struct chip_t *)dev_id;
+       struct canfifo_t *fifo;
+
+       irq_register=can_read_reg(chip,SJAIR);
 //     DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);
 //     DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n",
-//                                     get_reg(chip_irq->chip_base_addr+SJASR));
+//                                     can_read_reg(chip,SJASR));
 
        if ((irq_register & (IR_BEI|IR_EPI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0)
                return;
 
-       fifo_irq=chip_irq->msgobj[0]->fifo;
+       if(!chip->msgobj[0]->flags & BUFFERS_ALLOCATED) {
+               CANMSG("sja1000p_irq_handler: called with device closed, irq_register 0x%02x\n", irq_register);
+               return;
+       }
+       fifo=chip->msgobj[0]->fifo;
 
        if ((irq_register & IR_RI) != 0) {
-               sja1000p_read(chip_irq,fifo_irq);
-               chip_irq->msgobj[0]->ret = 0;
-               if (waitqueue_active(&fifo_irq->readq))
-                       wake_up_interruptible(&fifo_irq->readq);
+               sja1000p_read(chip,fifo);
+               chip->msgobj[0]->ret = 0;
+               if (waitqueue_active(&fifo->readq))
+                       wake_up_interruptible(&fifo->readq);
        }
        if ((irq_register & IR_TI) != 0) {
-               chip_irq->msgobj[0]->ret = 0;
-               if (waitqueue_active(&fifo_irq->writeq))
-                       wake_up_interruptible(&fifo_irq->writeq);
+               chip->msgobj[0]->ret = 0;
+               sja1000p_irq_write_handler(chip,fifo);
        }
        if ((irq_register & (IR_EI|IR_BEI|IR_EPI|IR_DOI)) != 0) { 
                // Some error happened
-               CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n",
-                       get_reg(chip_irq->chip_base_addr+SJASR), irq_register);
+               status=can_read_reg(chip,SJASR);
+               error_code=can_read_reg(chip,SJAECC);
+               CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
+                       status, irq_register, error_code);
 // FIXME: chip should be brought to usable state. Transmission cancelled if in progress.
 // Reset flag set to 0 if chip is already off the bus. Full state report
-               chip_irq->msgobj[0]->ret=-1;
-               if (waitqueue_active(&fifo_irq->writeq))
-                       wake_up_interruptible(&fifo_irq->writeq);
-               if (waitqueue_active(&fifo_irq->readq))
-                       wake_up_interruptible(&fifo_irq->readq);
+               chip->msgobj[0]->ret=-1;
+               
+               if(error_code == 0xd9) {
+                       chip->msgobj[0]->ret= -ENXIO;
+                       /* no such device or address - no ACK received */
+               }
+               if(retransmitted++>MAX_RETR) {
+                       can_write_reg(chip, CMR_AT, SJACMR); // cancel any transmition
+                       retransmitted = 0;
+               }
+               if(status&SR_BS) {
+                       CANMSG("bus-off, resetting sja1000p\n");
+                       can_write_reg(chip, 0, SJAMOD);
+               }
+               
+               if (waitqueue_active(&fifo->writeq))
+                       wake_up_interruptible(&fifo->writeq);
+               if (waitqueue_active(&fifo->readq))
+                       wake_up_interruptible(&fifo->readq);
+       } else {
+               retransmitted=0;
        }
 
        return;
diff --git a/lincan/utils/Makefile b/lincan/utils/Makefile
new file mode 100644 (file)
index 0000000..09ad302
--- /dev/null
@@ -0,0 +1,40 @@
+# Makefile for the Linux CAN-bus driver.
+# Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+# This software is released under the GPL-License.
+# Version 0.7  6 Aug 2001
+#
+# Changes made by Pavel Pisa pisa@cmp.felk.cvut.cz as preliminary
+# study for OCERA Real Time CAN/CANOpen project ORTCAN
+#
+########## The following options can be changed ##########
+
+# Compiler
+CC = gcc
+
+CFLAGS = -I../include -O2
+
+all: default
+
+default: utils
+
+dep:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M *.c $(MORE_C_FILES) > .depend
+
+install:
+       echo Nothing to install
+
+utils: rxtx sendburst readburst send can-proxy
+
+rxtx: rxtx.o
+
+sendburst: sendburst.o
+
+readburst: readburst.o
+
+send: send.o
+
+clean :
+       rm -f rxtx sendburst readburst send can-proxy *.o .depend
+
+-include .depend
+
diff --git a/lincan/utils/can-proxy.c b/lincan/utils/can-proxy.c
new file mode 100644 (file)
index 0000000..ab9bee8
--- /dev/null
@@ -0,0 +1,519 @@
+//#############################################################################
+/** @file                              can-proxy.c
+ @author:              T.Motylewski@bfad.de
+ Operating System:     LINUX
+ Compiler:                     gcc
+ Description:          gateway CAN-UDP.
+receives all CAN packets, prints them and may save them to a file.
+may send packets with ID, len, data entered from keyboard or from text file.
+may send to CAN packets received over UDP
+will forward packets from CAN to the most recent IP/UDP address.
+*/
+//#############################################################################
+
+
+//-----------------------------------------------------------------------------
+//                                  INCLUDES
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include "can.h"
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define DEFAULT_CAN_SERVER_PORT 3007
+#define DEFAULT_CAN_CLIENT_PORT 3008
+#define MAX_MSG_SIZE 4000
+
+typedef struct canmsg_t canmsg_t;
+
+extern int SendCanMsg(canmsg_t * msg);
+extern int ReceiveCanMsg(canmsg_t * msg);
+extern int ReadInput(int fd);
+
+
+/** tm means time in units of 1/100 s since program started (tsStarted)
+ * tm time stays positive for 24.8 days after system boot.
+ * It can be redefined by changing TM_HZ value to something else than 1000.
+ * Always use TM_HZ when comparing time with real seconds.
+ * The code should work after "time wraparound" but if something happens you know why.
+ * ts means time in sec */
+#define TM_HZ 1000
+
+
+#define MSG_CAN_UNKNOWN -1
+#define MSG_CAN_NONE 0
+#define TRUE 1
+#define FALSE 0
+#define CAN_MSG_SIZE sizeof(canmsg_t)
+#define CAN_DEV "/dev/can0"
+
+enum BusStateFlags {
+       BusReset = 1,
+       BusLocked = 1<<1
+};
+
+#define WARN(fmt...) (fprintf(stderr,"WARN:" fmt),fprintf(stderr,"\n"))
+#define ERR(fmt...) (fprintf(stderr,"ERROR:" fmt),fprintf(stderr,"\n"))
+
+#ifdef DEBUG
+       //#define DMSG(fmt...) (fprintf(stderr,"DBG:" fmt),fprintf(stderr," %f\n",gettime()))
+       //very usefull for debugging data change after some miliseconds combined with dumpnc.c
+
+       #define DMSG(fmt...) (fprintf(stderr,"DBG:" fmt),fprintf(stderr,"\n"))
+#else
+       #define DMSG(fmt...)
+#endif
+
+
+/** global variables */
+
+unsigned short int myport;
+unsigned short int toport;
+struct sockaddr_in myaddr, fromaddr, recvaddr, toaddr;
+
+
+int fdCanDev;
+int fdNet;
+int fdError;
+int fdIn;
+FILE * fLog;
+long iBusFlags;
+int bBusLock=0;
+time_t tsStarted;
+long tmWhenLocked;
+long tmDurationLocked;
+long tmLastVerified=0;
+long tmNow;  // current time, global, will be updated in many places
+long tmLastSentReceived=0;
+struct timeval tvNow;
+struct timeval tvSelectTimeout;
+double time0;
+double SleepUntil=0;
+
+int quiet = 0;
+
+
+long tmGet() {
+       gettimeofday(&tvNow,NULL);
+       return (tmNow=TM_HZ*(tvNow.tv_sec-tsStarted) + (TM_HZ*tvNow.tv_usec)/1000000);
+#if TM_HZ>2147
+#error when using 32 bit signed int TM_HZ can not be greater than 2147
+#endif
+}
+
+double gettime() {
+       gettimeofday(&tvNow,NULL);
+       return ( tvNow.tv_sec + tvNow.tv_usec/1000000.0);
+}
+
+/**
+       removes '\r\n' and all spaces and tabs from the end of string str
+       @param str: input/output string
+       @return final string length (without terminating \0) */
+int RemoveNL(char *str)
+{
+       int iLength;
+       for(iLength = strlen(str)-1; iLength >=0; iLength --) {
+               //DMSG("RmNL LineLength:>%i<", iLength);
+               if (isspace(str[iLength])) {
+                       str[iLength] = '\0';
+               }
+               else
+                       break;
+       }
+       return iLength+1;
+}
+
+
+/**
+       sending data over tcp/ip
+       @param fd       - file descriptor for connection
+       @param msg      - pointer to message to be written
+       @param size     - size of message
+       @return result of sendto */
+int WriteNet(int fd, void * msg, int size) {
+       return sendto(fd, msg, size, 0, (struct sockaddr*)&toaddr, sizeof(toaddr));
+}
+
+/**
+       reading data over tcp/ip
+       @param fd       - file descriptor for connection
+       @param msg      - pointer to message to be read
+       @param size     - size of message
+       @return result of recvfrom */
+int ReadNet(int fd, void * msg, int size) {
+       char recvbuf[MAX_MSG_SIZE];
+       int ret;
+       int recvaddrsize = sizeof(recvaddr);
+
+       // setting recvaddr is required for non-connected sockets
+       memcpy(&recvaddr, &fromaddr, sizeof(recvaddr));
+       ret = recvfrom(fd, recvbuf, MAX_MSG_SIZE, 0, (struct sockaddr*)& recvaddr, &recvaddrsize);
+//  DMSG("NET: %d", ret);
+       if(ret>size)
+               ret = size;
+       if(ret>0)
+               memcpy(msg, recvbuf, size);
+       return ret;
+}
+
+
+
+/**
+       handling command line options, calling functions, main program loop 
+       @param argc, char * argv[]      - command line options
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int main(int argc, char * argv[]) {
+       struct timeval tvTimeoutTmp;
+       int fdSelectMax;
+//     int ret;
+       int opt;
+       fd_set readsel;
+       canmsg_t canmsg;
+
+       myport = DEFAULT_CAN_SERVER_PORT;
+       toport = DEFAULT_CAN_CLIENT_PORT;
+       fdNet = fdCanDev = fdIn = -1;
+       fLog = NULL;
+       
+       iBusFlags = 0;
+       tmWhenLocked = tmDurationLocked = 0;
+       time0 = gettime();
+       tsStarted = tvNow.tv_sec;
+       tvSelectTimeout.tv_sec = 0;
+       tvSelectTimeout.tv_usec = 500000; // wake up every 0.5 s even without data
+
+       while((opt=getopt(argc, argv, "io:p:c:l"))>0) {
+               switch(opt) {
+               case 'i': // interactive or stdin
+                       fdIn = 0;
+                       break;
+               case 'o': // log file
+                       fLog = fopen(optarg,"a");
+                       break;
+               case 'p':
+                       sscanf(optarg,"%hi", &myport);
+                       break;
+               case 'c':
+                       fdCanDev = open(optarg,O_RDWR/*|O_NONBLOCK - select supported*/);
+                       break;
+               case 'l': // lock the bus during dispense
+                       bBusLock = 1;
+                       break;
+               case 'q':
+                       quiet ++;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if(!quiet)
+               fprintf(stderr, "can-proxy v0.7.1-pi3.3 (C) 2002 BFAD GmbH http://www.getembedded.de/ (GPL) \n");
+
+       
+       if(fdCanDev<0)
+               fdCanDev = open(CAN_DEV,O_RDWR|O_NONBLOCK);
+       fdNet = socket(AF_INET,SOCK_DGRAM,0);
+       memset(&myaddr, 0, sizeof(myaddr));
+       memset(&fromaddr, 0, sizeof(fromaddr));
+       memset(&toaddr, 0, sizeof(toaddr));
+
+       memset(& canmsg, 0, sizeof(canmsg));
+       myaddr.sin_family=AF_INET;
+       myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+       myaddr.sin_port = htons(myport) ;
+
+       toaddr.sin_family=AF_INET;
+       toaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);;
+       toaddr.sin_port = htons(toport);
+
+       bind(fdNet,(struct sockaddr*) &myaddr,sizeof(myaddr));
+
+       if(fdCanDev< 0 ) {
+               perror(CAN_DEV);
+               ERR("1.CAN-PROXY main fdCanDev not valid:%d, exiting", fdCanDev);
+               exit(1);
+       }
+
+       while(1) {
+               tvTimeoutTmp = tvSelectTimeout;
+               fdSelectMax=0;
+               FD_ZERO(&readsel);
+               if(fdCanDev>=0){
+                       FD_SET(fdCanDev, &readsel);
+                       if(fdCanDev+1>fdSelectMax)
+                               fdSelectMax = fdCanDev+1;
+               }
+               if(fdNet>=0) {
+                        FD_SET(fdNet, &readsel);
+                        if(fdNet+1>fdSelectMax)
+                                fdSelectMax = fdNet+1;
+               }
+               if(fdIn>=0) {
+                        FD_SET(fdIn, &readsel);
+                        if(fdIn+1>fdSelectMax)
+                                fdSelectMax = fdIn+1;
+               }
+               select(fdSelectMax, &readsel, NULL, NULL, &tvTimeoutTmp);
+               if(fdCanDev>=0 && FD_ISSET(fdCanDev, &readsel)) {
+                       if(ReceiveCanMsg(&canmsg) == 0) {
+                               WriteNet(fdNet, &canmsg, sizeof(canmsg));
+                               continue; // reading CAN has priority
+                       }
+               }
+               if(gettime()-time0 < SleepUntil) {
+                       continue;
+               }
+               if(fdNet>=0 && FD_ISSET(fdNet,&readsel)) {
+                       ReadNet(fdNet, &canmsg, sizeof(canmsg));
+                       // TODO: this will work for a single client
+                       // multiple clients should probably use broadcast
+                       //  for now we just reply to the most recent address
+                       toaddr = recvaddr;
+                       SendCanMsg(&canmsg);
+               }
+               if(fdIn>=0 && FD_ISSET(fdIn, &readsel)) {
+                       ReadInput(fdIn);
+               }
+//             usleep(20000); //can driver does select(), no need for delay
+       }
+       return 0;       
+}
+
+/**
+       logging messages to/from CAN
+       @param dir      - direction
+       @param fout - file descriptor for output
+       @param msg      - CanMsgPerma
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int LogMsg(char * dir, FILE *fout, canmsg_t * msg) {
+       int i;
+       double t;
+
+       t = gettime()-time0;
+       if(msg->length < 0)
+               msg->length = 0;
+       if(msg->length > 8)
+               msg->length = 8;
+
+       fprintf(stdout,"%s %8.3f  id=%08lx n=%d", 
+               dir, gettime()-time0, msg->id, msg->length);
+       for(i=0; i< msg->length; i++) {
+               fprintf(stdout, " %02x",  msg->data[i]);
+       }
+       fprintf(stdout, "\n");
+       fflush(stdout);
+
+       if(!fout) 
+               return 0;
+
+       fprintf(fout,"%s %8.3f  id=%08lx n=%d", 
+               dir, gettime()-time0, msg->id, msg->length);
+       for(i=0; i< msg->length; i++) {
+               fprintf(fout, " %02x",  msg->data[i]);
+       }
+       fprintf(fout, "\n");
+       fflush(fout);
+
+       return 0;
+}
+
+
+/** PERMA CAN utility functions */
+
+/**
+       sending messages to CAN
+       @param msg      - CanMsgPerma
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int SendCanMsg(canmsg_t * msg) {
+       int ret;
+
+       msg->flags = MSG_EXT;
+       msg->cob = 0;
+       tmGet();
+       ret=write(fdCanDev, msg, CAN_MSG_SIZE);
+       LogMsg("SEND", fLog, msg);
+       tmLastSentReceived = tmNow;
+       if( ret != CAN_MSG_SIZE) {
+               perror("sending to CAN");
+//TODO: send to error_ico
+               return ret;
+       }
+       return 0;
+}
+       
+/**
+       receiving messages from CAN
+       @param msg      - CanMsgPerma
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int ReceiveCanMsg(canmsg_t * msg) {
+       int ret;
+//     double t;
+//     fdCanDev = open(CAN_DEV,O_RDWR | O_NONBLOCK);
+
+       msg->flags = 0;
+       msg->cob = 0;
+       msg->timestamp = 0;
+       ret = read(fdCanDev,msg, CAN_MSG_SIZE);
+       if(ret == CAN_MSG_SIZE) {       
+               LogMsg("RECV", fLog, msg);
+               tmLastSentReceived = tmNow;
+               return 0;
+       }
+       // we can receive 0 here
+       if(ret == 0 || (ret == -1 && errno == EAGAIN)) {
+               return -EAGAIN;
+       }
+       DMSG("received %d bytes",ret);
+       return ret;
+}
+
+/** @name GetNumber
+       aliasing: deassign
+       @param buf      - string buffer
+       @param val      - alias value
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int GetNumber(char * buf, int * val) {
+       if(!buf) {
+               return -1;
+       }
+       if(sscanf(buf,"%i", val)==1) {
+               return 0;
+       }
+       return -1;
+}
+
+/** @name BuildCanMsg
+       building the can message from buf string to msg
+       @param buf      - 
+       @param msg      - CanMsgPerma
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int BuildCanMsg(char * buf, canmsg_t *msg) {
+       int val;
+       int i;
+
+       buf = strtok(buf, " \t");
+
+       val = msg->id;
+       buf = strtok(NULL, " \t");
+       GetNumber(buf, &val);
+       msg->id = val;
+
+       val = msg->length;
+       buf = strtok(NULL, " \t");
+       GetNumber(buf, &val);
+       msg->length = val;
+
+       for(i=0;(buf = strtok(NULL, " \t")); i++) {
+               val = msg->data[i];
+               GetNumber(buf, &val);
+               msg->data[i] = val;
+       }
+       return 0;
+}
+
+
+#define LINE_L 66000
+char buf[LINE_L];
+
+extern int ReadCommand(char *buf);
+
+
+/**
+       processing a script or from stdin
+       @param fd       - file descriptor
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int ReadInput(int fd) {
+       int ret;
+       int i,j;
+       ret = read(fd, buf, LINE_L);
+       for(i=0; i< ret; ) {
+               for(j=i; (j<ret) && (buf[j] != '\n'); j++); // find NL
+               if(j<ret) {
+                       buf[j] = '\0';
+                       ReadCommand(buf+i);
+                       i=j+1;
+               } else {
+                       fprintf(stderr, "too big input file\n");
+                       i=j;
+               }
+       }
+       return 0;
+}
+
+/**
+       reading and handling commands from buf string
+       @param buf      - string buffer, 1.char tells about what is to be done: 
+                                                                w - write 
+                                                                s - sleep
+                                                                a - assign (simple aliasing mechanism)
+                                                                r - reset timer
+                                                                l - lock the bus
+                                                                q - quit application
+       @return  0                                      - OK
+                       -1                                      - ERROR */
+int ReadCommand(char *buf) {
+       static int usSleep=20000;
+       char * ptr;
+       static canmsg_t msg;
+
+       buf[LINE_L-1] = '\0';
+       if(RemoveNL(buf) == 0)
+               return 0; // empty line
+
+       switch(tolower(buf[0])) {
+       case 'q':
+               DMSG("1.CAN-PROXY ReadCommand received QUIT command, exiting");
+               exit(0);
+               break;
+       case 'r':
+               time0 = gettime();
+               break;
+       case 't':
+               printf("TIME %8.3f\n", gettime()-time0);
+               break;
+       case 's':
+               strtok(buf, " \t");
+               ptr = strtok(NULL, " \t");
+               if(ptr)
+                       sscanf(ptr,"%i", &usSleep);
+               SleepUntil = gettime()-time0 + usSleep/1000000.0;
+               break;
+       case 'l':
+               strtok(buf, " \t");
+               printf("bus locking is %s", (bBusLock ? "ON" : "OFF"));
+               ptr = strtok(NULL, " \t");
+               if(ptr)
+                       sscanf(ptr,"%i", &bBusLock);
+               printf(" switched to %s\n", (bBusLock ? "ON" : "OFF"));
+               break;
+       case 'w':
+               if(BuildCanMsg(buf, &msg) == 0) {
+                       SendCanMsg(&msg);
+               } else {
+                       fprintf(stderr,"wrong message syntax: %s\n", buf);
+               }
+               break;
+       }
+       return 0;
+}
+
index 139e558..8c61069 100644 (file)
@@ -1,14 +1,32 @@
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <signal.h>
 
 #include "../include/can.h"
 
 int fd;
 
+int can_fd_wait(int fd, int wait_sec)
+{
+  int ret;
+  struct timeval timeout;
+  fd_set set;
+
+  FD_ZERO (&set);
+  FD_SET (fd, &set);
+  timeout.tv_sec = wait_sec;
+  timeout.tv_usec = 0;
+  while ((ret=select(FD_SETSIZE,&set, NULL, NULL,&timeout))==-1
+          &&errno==-EINTR);
+  return ret;
+}
+
+
 /*--- handler on SIGINT signal : the program quit with CTL-C ---*/
 void sortie(int sig)
        {
@@ -43,11 +61,19 @@ int main(void)
                readmsg.flags=0;
                readmsg.cob=0;
                readmsg.timestamp=0;
+           #if 1
+               ret=can_fd_wait(fd, 5);
+               printf("can_fd_wait returnet %d\n",ret);
+           #endif
                ret=read(fd,&readmsg,sizeof(struct canmsg_t));
                if(ret <0) 
                        {
                        printf("Error reading message\n");
                        }
+               else if(ret == 0)
+                       {
+                       printf("No message arrived\n");
+                       }
                else 
                        {
                        printf("Received message #%lu: id=%lX dlc=%u",i,readmsg.id,readmsg.length);
index 0adcef1..5fe75eb 100644 (file)
@@ -38,7 +38,7 @@ int main(void)
                remote[count]='\0';
        }
        if (remote[0]=='y')
-               message.flags |= MSG_RTR;
+               message.flags = MSG_RTR;
        else
                message.flags = 0;
 //     message.flags |= MSG_EXT;  hard code EXT for now
@@ -55,6 +55,8 @@ int main(void)
                        specialfile[MAXL]='\0';
                printf("Enter the Message ID ");
                scanf("%lx",&message.id);
+               if(message.id>=(1<<11))
+                 message.flags |= MSG_EXT;
                printf("Enter the Message Length ");
                scanf("%d",&message.length);
                for (i=0; i<message.length; i++) {
@@ -72,7 +74,7 @@ int main(void)
                                strncpy(specialfile,buf,MAXL);
                        specialfile[MAXL]='\0';
                printf("Enter the Message ID ");
-               scanf("%ld",&message.id);
+               scanf("%lx",&message.id);
                getchar();
        }
 
diff --git a/lincan/utils/send.c b/lincan/utils/send.c
new file mode 100644 (file)
index 0000000..c8373b1
--- /dev/null
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "../include/can.h"
+#define MAXL 40
+
+int main(void)
+{
+       int i=0, fd=0, ret=0, count=0;
+       char loop=0;
+       unsigned long bits;
+       char ch, transmission[MAXL+1], specialfile[MAXL+1]="/dev/can0", emptystring[MAXL+1]="", buf[MAXL+1];
+       char remote[MAXL+1];
+       struct canmsg_t message;
+
+       printf("\nThis program allows you to send  a stream of Can messages.\n");
+       printf("Please answer the following questions:\n\n");
+
+//             message.flags = 0;
+       message.flags |= MSG_EXT;  //hard code EXT for now
+
+       printf("From wich device file would you like to send the message?\n");
+       printf(specialfile);
+       *buf='\0';
+       fgets(buf,MAXL,stdin);
+       buf[strcspn(buf,"\n")]='\0';
+       if(*buf)
+               strncpy(specialfile,buf,MAXL);
+       specialfile[MAXL]='\0';
+       printf("Enter the starting Message ID ");
+       scanf("%lx",&message.id);
+       printf("Enter the Message Length ");
+       scanf("%d",&message.length);
+       for (i=0; i<message.length; i++) {
+               printf("Enter data byte [%d] ",i);
+               scanf("%x",(int *)&message.data[i]);
+       }
+
+       fd=open(specialfile,O_RDWR);
+       if (fd<0) {
+               printf("Error opening %s\n",specialfile);
+               return -1;
+       }
+
+       bits=0;
+       while(1) {
+               message.flags = MSG_EXT;
+               message.id++;
+               message.length %= 8;
+               message.length++;
+               bits += 8*(4+message.length);
+               memcpy(message.data,&bits,sizeof(bits));
+               ret=write(fd, &message, sizeof(struct canmsg_t));
+               if (ret<0)
+                       printf("Error sending message from %s\n",specialfile);
+       }
+
+       if (close(fd)) {
+               printf("Error closing %s\n",specialfile);
+               return -1;
+       }
+
+       return 0;
+}