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
# 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) $@ ; )
+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.
- 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:
- 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)
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
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 */
/* 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
#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)
/* 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)
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);
#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 {
* 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;
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 {
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
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;
/* 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;
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;
--- /dev/null
+/* 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);
+
--- /dev/null
+/* 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);
--- /dev/null
+# 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
--- /dev/null
+/* 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;
+}
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);
/* 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;
}
#include <linux/fs.h>
#include <linux/version.h>
+#include <linux/string.h>
#include "../include/main.h"
#include "../include/ioctl.h"
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
fifo->rx_in_progress = 0;
fifo->tx_in_progress = 0;
- fifo->head = fifo->tail = 0; //TEMP!!
-
break;
}
#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)
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!
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;
}
{
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;
}
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;
}
}
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);
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);
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);
+}
#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"
#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"
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;
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,
owner: THIS_MODULE,
read: can_read,
write: can_write,
+ poll: can_poll,
ioctl: can_ioctl,
open: can_open,
release: can_close,
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")) {
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
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++;
#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>
}
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;
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++;
}
#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"
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
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;
}
--- /dev/null
+/* 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;
+}
#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
*/
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;
}
*/
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;
}
*/
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
{
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;
*/
void pcm3680_write_register(unsigned char data, unsigned long address)
{
- writeb(data,address);
+ writeb(data,isa_base+address);
}
/**
*/
unsigned pcm3680_read_register(unsigned long address)
{
- return readb(address);
+ return readb(isa_base+address);
}
/* !!! Don't change this function !!! */
--- /dev/null
+/* 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;
+}
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <linux/string.h>
#include <asm/errno.h>
#include <asm/io.h>
#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>
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
/* 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)
*/
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
{
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
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,
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;
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,
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;
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;
* 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>
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;
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;
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);
--- /dev/null
+/* 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;
+}
* 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"
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);
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) {
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;
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);
}
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);
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;
}
// 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
#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;
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++;
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++;
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;
}
{
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
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);
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;
--- /dev/null
+# 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
+
--- /dev/null
+//#############################################################################
+/** @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;
+}
+
#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)
{
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);
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
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++) {
strncpy(specialfile,buf,MAXL);
specialfile[MAXL]='\0';
printf("Enter the Message ID ");
- scanf("%ld",&message.id);
+ scanf("%lx",&message.id);
getchar();
}
--- /dev/null
+#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;
+}