From: ppisa Date: Tue, 29 Apr 2003 22:40:59 +0000 (+0000) Subject: The first enhanced version of Linux CAN-bus driver for OCERA project X-Git-Tag: CLT_COMM_CAN_pre_canmsg_change~31 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/786c7d54e8d820e89997e507c29ea716c0d55fd9?ds=sidebyside The first enhanced version of Linux CAN-bus driver for OCERA project can-0.7.1-pi3.5 (pisa@cmp.felk.cvut.cz) --- diff --git a/lincan/CREDITS b/lincan/CREDITS index 7d84faa..781baf9 100644 --- a/lincan/CREDITS +++ b/lincan/CREDITS @@ -4,3 +4,9 @@ I would like to thank all who have contributed to this project and especially: Tomasz Motylewski, T.Motylewski@bfad.de BFAD GmbH http://www.bfad.de/, http://www.getembedded.de/ Tester, bugfixes, hints and PeliCAN mode! + He provided ETHERNET CAN-PROXY as well. + +Pavel Pisa, pisa@cmp.felk.cvut.cz +http://cmp.felk.cvut.cz/~pisa, http://www.pikron.com + Bugfixes in SJA1000 code. Many other changes. + Most of new bugs belong to me. \ No newline at end of file diff --git a/lincan/Makefile b/lincan/Makefile index 75a1182..28722b9 100644 --- a/lincan/Makefile +++ b/lincan/Makefile @@ -2,219 +2,22 @@ # 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 $(> .support -pccan.o : pccan.c pccan.h - $(CC) -c -o $(> .support -smartcan.o : smartcan.c smartcan.h - $(CC) -c -o $(> .support -nsi.o : nsi.c nsi.h - $(CC) -c -o $(> .support -cc_can104.o : cc_can104.c cc_can104.h - $(CC) -c -o $(> .support -aim104.o : aim104.c aim104.h - $(CC) -c -o $(> .support -pc-i03.o : pc-i03.c pc-i03.h - $(CC) -c -o $(> .support -pcm3680.o : pcm3680.c pcm3680.h - $(CC) -c -o $(> .support -m437.o : m437.c m437.h - $(CC) -c -o $(> .support -pcccan.o : pcccan.c pcccan.h - $(CC) -c -o $(> .support -ssv.o : ssv.c ssv.h - $(CC) -c -o $(> .support -template.o : template.c template.h - $(CC) -c -o $(> .support -open.o : open.c open.h - $(CC) -c -o $(, sets the baudrate of the device(s) +- clock_freq=, the frequency of the CAN quartz - stdmask=, sets the standard mask of the device - extmask=, sets the extended mask of the device - mo15mask=, sets the mask for message object 15 (i82527 only) diff --git a/lincan/TODO b/lincan/TODO index f0d17cd..7a4c555 100644 --- a/lincan/TODO +++ b/lincan/TODO @@ -3,8 +3,12 @@ Written by Arnaud Westenberg email:arnaud@wanadoo.nl This software is released under the GPL-License. Version 0.7 6 Aug 2001 ++ Poll/select + - Add proper comment to the code - Error handling/reporting - Proc directory - Lot of ioctl's -- Poll/select + +- Get rid of CLI and STI, they are not longer supported + in 2.5.xx kernels diff --git a/lincan/include/can.h b/lincan/include/can.h index 071deae..6ccb6dc 100644 --- a/lincan/include/can.h +++ b/lincan/include/can.h @@ -13,7 +13,7 @@ struct canmsg_t { unsigned long id; unsigned long timestamp; unsigned int length; - char data[CAN_MSG_LENGTH]; + unsigned char data[CAN_MSG_LENGTH]; } PACKED; /* Definitions to use for canmsg_t flags */ @@ -24,15 +24,15 @@ struct canmsg_t { /* CAN ioctl magic number */ #define CAN_IOC_MAGIC 'd' -unsigned long bittiming; -unsigned short channel; +typedef unsigned long bittiming_t; +typedef unsigned short channel_t; /* CAN ioctl functions */ -#define CMD_START _IOW(CAN_IOC_MAGIC, 1, channel) -#define CMD_STOP _IOW(CAN_IOC_MAGIC, 2, channel) +#define CMD_START _IOW(CAN_IOC_MAGIC, 1, channel_t) +#define CMD_STOP _IOW(CAN_IOC_MAGIC, 2, channel_t) //#define CMD_RESET 3 -#define CONF_BAUD _IOW(CAN_IOC_MAGIC, 4, bittiming) +#define CONF_BAUD _IOW(CAN_IOC_MAGIC, 4, bittiming_t) //#define CONF_ACCM //#define CONF_XTDACCM //#define CONF_TIMING diff --git a/lincan/include/constants.h b/lincan/include/constants.h index f662a98..10af2ce 100644 --- a/lincan/include/constants.h +++ b/lincan/include/constants.h @@ -26,6 +26,7 @@ #define MAX_HW_CARDS 8 #define MAX_HW_CHIPS 4 #define MAX_TOT_CHIPS (MAX_HW_CHIPS*MAX_HW_CARDS) +#define MAX_TOT_CHIPS_STR 32 /* must be explicit for MODULE_PARM */ #define MAX_IRQ 32 #define MAX_MSGOBJS 15 #define MAX_TOT_MSGOBJS (MAX_TOT_CHIPS*MAX_MSGOBJS) @@ -39,6 +40,7 @@ /* These flags can be used for the msgobj_t structure flags data entry */ #define OPENED (1<<0) +#define BUFFERS_ALLOCATED (1<<1) /* These flags can be used for the chip_t structure flags data entry */ #define CONFIGURED (1<<0) diff --git a/lincan/include/irq.h b/lincan/include/irq.h index 6391bf9..7410882 100644 --- a/lincan/include/irq.h +++ b/lincan/include/irq.h @@ -7,3 +7,4 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs); void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +void dummy_irq_handler(int irq, void *dev_id, struct pt_regs *regs); diff --git a/lincan/include/main.h b/lincan/include/main.h index 53fb783..c811d87 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -21,9 +21,17 @@ #define CANMSG(fmt,args...) printk(KERN_ERR "can.o: " fmt,##args) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) + #define MINOR_NR \ (MINOR(file->f_dentry->d_inode->i_rdev)) +#else /* Linux kernel > 2.5.7 */ + +#define MINOR_NR \ + (minor(file->f_dentry->d_inode->i_rdev)) +#endif /* Linux kernel > 2.5.7 */ + #define MSG_OFFSET(object) ((object)*0x10) struct canhardware_t { @@ -159,7 +167,7 @@ struct mem_addr { * The rx/tx_in_progress entries are used to determine whether the device is * already set up for transmission. */ -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) struct canfifo_t { struct wait_queue *readq, *writeq; struct canmsg_t *buf_tx_entry; @@ -170,7 +178,7 @@ struct canfifo_t { struct canmsg_t *rx_readp; int rx_size, tx_size; volatile int rx_in_progress, tx_in_progress; - int head, tail; //TEMP!!! + /*int head, tail;*/ /* removed */ }; #else struct canfifo_t { @@ -184,7 +192,7 @@ struct canfifo_t { struct canmsg_t *rx_readp; int rx_size, tx_size; volatile int rx_in_progress, tx_in_progress; - int head, tail; //TEMP!!! + /*int head, tail;*/ /* removed */ }; #endif @@ -192,7 +200,7 @@ struct canfifo_t { struct rtr_id { unsigned long id; struct canmsg_t *rtr_message; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) struct wait_queue *rtr_wq; #else struct __wait_queue_head rtr_wq; @@ -218,7 +226,7 @@ extern struct mem_addr *mem_head; /* Inline function to write to the hardware registers. The argument address is * relative to the memory map of the chip and not the absolute memory address. */ -extern inline void can_write_reg(struct chip_t *chip, unsigned char data, unsigned short address) +extern inline void can_write_reg(const struct chip_t *chip, unsigned char data, unsigned short address) { unsigned short segment_number; unsigned long address_to_write; @@ -233,7 +241,7 @@ extern inline void can_write_reg(struct chip_t *chip, unsigned char data, unsign chip->hostdevice->hwspecops->write_register(data, address_to_write); } -extern inline unsigned can_read_reg(struct chip_t *chip, unsigned short address) +extern inline unsigned can_read_reg(const struct chip_t *chip, unsigned short address) { unsigned short segment_number; unsigned long address_to_read; diff --git a/lincan/include/pikronisa.h b/lincan/include/pikronisa.h new file mode 100644 index 0000000..7fa56dd --- /dev/null +++ b/lincan/include/pikronisa.h @@ -0,0 +1,21 @@ +/* pikronisa.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * This software is released under the GPL-License. + * Version 0.7 6 Aug 2001 + * + * Support for PiKRON Ltd ISA CAN card using + * memory mapped SJA1000 controller + * Added by Pavel Pisa pisa@cmp.felk.cvut.cz + */ + +int pikronisa_request_io(unsigned long io_addr); +int pikronisa_release_io(unsigned long io_addr); +int pikronisa_reset(int card); +int pikronisa_init_hw_data(int card); +int pikronisa_init_chip_data(int card, int chipnr); +int pikronisa_init_obj_data(int chipnr, int objnr); +void pikronisa_write_register(unsigned char data, unsigned long address); +unsigned pikronisa_read_register(unsigned long address); +int pikronisa_program_irq(int card); + diff --git a/lincan/include/select.h b/lincan/include/select.h new file mode 100644 index 0000000..cdf9195 --- /dev/null +++ b/lincan/include/select.h @@ -0,0 +1,10 @@ +/* select.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * This software is released under the GPL-License. + * Version 0.7.1-pi2 15 Nov 2002 + * + * added by Pavel Pisa pisa@cmp.felk.cvut.cz + */ + +unsigned int can_poll(struct file *file, poll_table *wait); diff --git a/lincan/src/Makefile b/lincan/src/Makefile new file mode 100644 index 0000000..b83aa6d --- /dev/null +++ b/lincan/src/Makefile @@ -0,0 +1,150 @@ +# Makefile for the Linux CAN-bus driver. +# Written by Arnaud Westenberg email:arnaud@wanadoo.nl +# This software is released under the GPL-License. +# Version 0.7 6 Aug 2001 +# +# This version is adapted from uLan Communication driver +# (C) Copyright 1999 by Pavel Pisa pisa@cmp.felk.cvut.cz +# +#***************************************************************** + +# Where to look for kernel +# if not defined, sources of current running kernel are found +#KERNEL_LOCATION=/usr/src/linux +#KERNEL_LOCATION=/usr/src/linux-2.2.19 +#KERNEL_LOCATION=/usr/src/linux-2.2.22 +#KERNEL_LOCATION=/usr/src/linux-2.5.47 + +# Comment-out next two lines, if you do not build driver +# in the OCERA source tree +TOP=../../../../.. +KERNEL_LOCATION=$(TOP)/kernel/linux + +# Enable debugging messages +DEBUG = y + +# You can comment out the hardware you don't need. This will result in a smaller +# driver. By default, all hardware is supported in the driver. See the README +# file for a description of the supported hardware. +# pccan Not to be confused with PCCCAN!!! +# pcccan Not to be confused with PCCAN!!! + +SUPPORTED_CARDS = pip pccan smartcan nsi cc_can104 \ + pc_i03 pcm3680 aim104 m437 pcccan ssv \ + bfadcan pikronisa template + +########## Don't change anything under this line ################ + +# currently running kernel +CURRENT=$(shell uname -r) +KERNEL_NEW=$(shell if [ -d /lib/modules/$(CURRENT)/build ] ; \ + then echo yes ; else echo no ; fi ) + +#KERNEL_LOCATION=/usr/src/kernel/$(CURRENT) +#KERNEL_LOCATION=/lib/modules/$(CURRENT)/build + +ifndef KERNEL_LOCATION +ifeq ($(KERNEL_NEW),yes) +KERNEL_LOCATION=/lib/modules/$(CURRENT)/build +MODULE_CHAR_LOC=/lib/modules/$(CURRENT)/kernel/drivers/char +else +KERNEL_LOCATION=/usr/src/linux +MODULE_CHAR_LOC=/lib/modules/$(CURRENT)/misc +endif +endif + +KERNEL_VERSION := $(shell awk -F\" '/REL/ {print $$2}' \ + $(KERNEL_LOCATION)/include/linux/version.h | awk -F\- '{print $$1}') + +PROC_FS := $(shell awk -F\ '/PROC_FS/ {print $$3}' \ + $(KERNEL_LOCATION)/include/linux/autoconf.h) + +DEVFS_FS := $(shell awk -F\ '/DEVFS_FS/ {print $$3}' \ + $(KERNEL_LOCATION)/include/linux/autoconf.h) + +KERNEL_MODULE_V26 := $(shell echo $(KERNEL_VERSION) \ + | sed -n 's/^.*2\.[5-9]\..*$$/yes/p') + +ifdef DEBUG + EXTRA_CFLAGS += -DCAN_DEBUG + EXTRA_CFLAGS += -ggdb +endif + +ifndef MODVERSIONS +# EXTRA_CFLAGS += -DNOVER +#else +# EXTRA_CFLAGS += -DMODVERSIONS +endif + +ifdef DEVFS_FS + EXTRA_CFLAGS += -DWITH_DEVFS_FS +endif + +ifdef PROC_FS + O_OBJS += proc.o +endif + +# Target object file if any +# this must be undefined for 2.5.xx kernels +ifndef KERNEL_MODULE_V26 +O_TARGET = can.o +endif +# Regular object files +O_OBJS += $(SUPPORTED_CARDS:%=%.o) +O_OBJS += main.o modparms.o setup.o sja1000.o i82527.o close.o ioctl.o \ + open.o write.o read.o sja1000p.o irq.o select.o +# Objects with exported symbols (-DEXPORT_SYMTAB) +OX_OBJS = +# Module objects +M_OBJS = $(O_TARGET) +# Module only objects with exported symbols (-DEXPORT_SYMTAB) +MX_OBJS = +# Kernel only objects +L_OBJS = +# Kernel only objects with exported symbols (-DEXPORT_SYMTAB) +LX_OBJS = +# Additional CFLAGS +EXTRA_CFLAGS += + +# Linux 2.4.2 build system needs next +can-objs := $(O_OBJS) +obj-y := $(O_OBJS) +obj-m := can.o + +########## Source/target independent buil of module ############# + +all : default + +default : make_this_module + cp can.o ../can.o + +dep: make_this_module_dep + +install : install_this_module + +.supported_cards.h: Makefile + echo >.supported_cards.h + $(foreach card, $(SUPPORTED_CARDS), \ + echo \#define ENABLE_CARD_$(card) 1 >>.supported_cards.h ;) + +make_this_module: .supported_cards.h + echo Linux kernel version $(KERNEL_VERSION) + echo Linux kernel sources $(KERNEL_LOCATION) + echo Module target $(obj-m) + echo Module objects $(can-objs) + DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR modules) + for f in $(obj-m:%.o=%) ; do if [ -f $$f.ko ] ; then cp -u $$f.ko $$f.o ; fi ; done + +make_this_module_dep: + DIR=`pwd`; (cd $(KERNEL_LOCATION); make SUBDIRS=$$DIR dep) + +install_this_module: make_this_module + su -c "mkdir -v -p $(MODULE_CHAR_LOC); cp -v $(obj-m) $(MODULE_CHAR_LOC)" + +clean: + rm -f $(M_OBJS) $(MX_OBJS) $(O_OBJS) $(OX_OBJS) $(obj-m) $(obj-m:%.o=%.ko) \ + .*.o.flags .*.o.cmd .depend .supported_cards.h *~ + +ifndef KERNEL_MODULE_V26 +include $(KERNEL_LOCATION)/Rules.make +endif diff --git a/lincan/src/bfadcan.c b/lincan/src/bfadcan.c new file mode 100644 index 0000000..930e91a --- /dev/null +++ b/lincan/src/bfadcan.c @@ -0,0 +1,342 @@ +/* bfadcan.c + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * This software is released under the GPL-License. + * Version 0.7 6 Aug 2001 + */ + +/* This file is intended as a bfadcan file for currently unsupported hardware. + * Once you've changed/added the functions specific to your hardware it is + * possible to load the driver with the hardware option hw=bfadcan. + */ + +#define __NO_VERSION__ /* this is not a main module, do not include module info */ + +#include +#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) +#define MODVERSIONS +#endif + +#if defined (MODVERSIONS) +#include +#endif +#include + +#include +#include +#include +#include +#include + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) +#include +#else +#include +#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; +} diff --git a/lincan/src/close.c b/lincan/src/close.c index 7ac3574..5f7d112 100644 --- a/lincan/src/close.c +++ b/lincan/src/close.c @@ -26,6 +26,7 @@ int can_close(struct inode *inode, struct file *file) { + objects_p[MINOR_NR]->flags &= ~BUFFERS_ALLOCATED; /* Give up message buffer memory */ if (objects_p[MINOR_NR]->fifo->buf_tx_entry) del_mem_from_list(objects_p[MINOR_NR]->fifo->buf_tx_entry); @@ -39,7 +40,8 @@ int can_close(struct inode *inode, struct file *file) /* FIXME: what about clearing chip HW status, stopping sending messages etc? */ objects_p[MINOR_NR]->flags &= ~OPENED; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50)) MOD_DEC_USE_COUNT; - +#endif return 0; } diff --git a/lincan/src/ioctl.c b/lincan/src/ioctl.c index 0f54c86..ec029ab 100644 --- a/lincan/src/ioctl.c +++ b/lincan/src/ioctl.c @@ -16,6 +16,7 @@ #include #include +#include #include "../include/main.h" #include "../include/ioctl.h" @@ -81,7 +82,7 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned fifo->rx_size= MAX_BUF_LENGTH * sizeof(struct canmsg_t); fifo->tx_size = fifo->rx_size; - #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) + #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) init_waitqueue(&fifo->readq); init_waitqueue(&fifo->writeq); #else @@ -92,8 +93,6 @@ int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned fifo->rx_in_progress = 0; fifo->tx_in_progress = 0; - fifo->head = fifo->tail = 0; //TEMP!! - break; } diff --git a/lincan/src/irq.c b/lincan/src/irq.c index 92ce53e..caf0ac6 100644 --- a/lincan/src/irq.c +++ b/lincan/src/irq.c @@ -17,7 +17,7 @@ #include #include -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) #include #else #include @@ -28,24 +28,29 @@ #include "../include/i82527.h" #include "../include/sja1000.h" -void i82527_irq_rtr_handler(void); -void sja1000_irq_read_handler(void); -void sja1000_irq_write_handler(void); +void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *msgobj, + struct rtr_id *rtr_search, unsigned long message_id); +void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj); +void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj); -void (*put_reg)(unsigned char data, unsigned long address); -unsigned (*get_reg)(unsigned long address); - -struct chip_t *chip=NULL; -struct candevice_t *device=NULL; +/*struct candevice_t *device=NULL; unsigned object=0,irq_register=0; unsigned long msgbase=0; struct canfifo_t *fifo=NULL; unsigned long message_id=0; struct rtr_id *rtr_search; +*/ -inline void i82527_irq_write_handler(void) +inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *msgobj) { - put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0); + struct canfifo_t *fifo=msgobj->fifo; + unsigned long msgbase=msgobj->obj_base_addr; + void (*write_reg)(unsigned char data, unsigned long address); + unsigned (*read_reg)(unsigned long address); + write_reg=chip->hostdevice->hwspecops->write_register; + read_reg=chip->hostdevice->hwspecops->read_register; + + (*write_reg)((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0); fifo->tx_readp++; if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) @@ -53,43 +58,48 @@ inline void i82527_irq_write_handler(void) if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty fifo->tx_in_progress = 0; if (waitqueue_active(&fifo->writeq)) { - chip->msgobj[object]->ret = 0; + msgobj->ret = 0; wake_up_interruptible(&fifo->writeq); } return; } - if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object], - fifo->tx_readp)) { + if (chip->chipspecops->pre_write_config(chip, msgobj, fifo->tx_readp)) { if (waitqueue_active(&fifo->writeq)) { - chip->msgobj[object]->ret = -1; + msgobj->ret = -1; wake_up_interruptible(&fifo->writeq); return; } } - if (chip->chipspecops->send_msg(chip, chip->msgobj[object], - fifo->tx_readp)) { + if (chip->chipspecops->send_msg(chip, msgobj, fifo->tx_readp)) { if (waitqueue_active(&fifo->writeq)) { - chip->msgobj[object]->ret = -1; + msgobj->ret = -1; wake_up_interruptible(&fifo->writeq); return; } } } -inline void i82527_irq_read_handler(void) +inline void i82527_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj, + unsigned long message_id) { int i=0, tmp=1 ; - + struct canfifo_t *fifo=msgobj->fifo; + unsigned long msgbase=msgobj->obj_base_addr; + void (*write_reg)(unsigned char data, unsigned long address); + unsigned (*read_reg)(unsigned long address); + write_reg=chip->hostdevice->hwspecops->write_register; + read_reg=chip->hostdevice->hwspecops->read_register; + while (tmp) { - put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase + + (*write_reg)((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase + iMSGCTL1); - put_reg((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase + + (*write_reg)((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase + iMSGCTL0); - fifo->rx_writep->length =(get_reg(msgbase+iMSGCFG) & 0xf0) >> 4; + fifo->rx_writep->length =((*read_reg)(msgbase+iMSGCFG) & 0xf0) >> 4; fifo->rx_writep->id = message_id; for (i=0; i < fifo->rx_writep->length; i++) - fifo->rx_writep->data[i] = get_reg(msgbase+iMSGDAT0+i); + fifo->rx_writep->data[i] = (*read_reg)(msgbase+iMSGDAT0+i); //FIXME: Add buffer overflow check, currently it's silently over written! @@ -97,7 +107,7 @@ inline void i82527_irq_read_handler(void) if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) fifo->rx_writep = fifo->buf_rx_entry; - if (!((tmp=get_reg(msgbase + iMSGCTL1)) & NEWD_SET)) { + if (!((tmp=(*read_reg)(msgbase + iMSGCTL1)) & NEWD_SET)) { break; } @@ -114,21 +124,30 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { int id0=0, id1=0, id2=0, id3=0; - chip=(struct chip_t *)dev_id; - device=(struct candevice_t *)chip->hostdevice; - - put_reg=device->hwspecops->write_register; - get_reg=device->hwspecops->read_register; + unsigned irq_register; + unsigned object; + struct chip_t *chip=(struct chip_t *)dev_id; + struct msgobj_t *msgobj; + unsigned long msgbase; + unsigned long message_id; + struct rtr_id *rtr_search; + void (*write_reg)(unsigned char data, unsigned long address); + unsigned (*read_reg)(unsigned long address); + write_reg=chip->hostdevice->hwspecops->write_register; + read_reg=chip->hostdevice->hwspecops->read_register; + + /*put_reg=device->hwspecops->write_register;*/ + /*get_reg=device->hwspecops->read_register;*/ if ( (chip->flags & SEGMENTED) != 0) - irq_register = get_reg(chip->chip_base_addr+iIRQ+SPACING); + irq_register = can_read_reg(chip, iIRQ+SPACING); else - irq_register = get_reg(chip->chip_base_addr+iIRQ); + irq_register = can_read_reg(chip, iIRQ); while (irq_register) { if (irq_register == 0x01) { - DEBUGMSG("Status register: 0x%x\n",get_reg(chip->chip_base_addr+iSTAT)); + DEBUGMSG("Status register: 0x%x\n",can_read_reg(chip, iSTAT)); return; } @@ -137,24 +156,24 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs) else object = irq_register-3; - fifo=chip->msgobj[object]->fifo; - msgbase=chip->msgobj[object]->obj_base_addr; + msgobj=chip->msgobj[object]; + msgbase=msgobj->obj_base_addr; - if (get_reg(msgbase+iMSGCFG) & MCFG_DIR) { - i82527_irq_write_handler(); + if ((*read_reg)(msgbase+iMSGCFG) & MCFG_DIR) { + i82527_irq_write_handler(chip, msgobj); } else { if (extended) { - id0=get_reg(msgbase+iMSGID3); - id1=get_reg(msgbase+iMSGID2)<<8; - id2=get_reg(msgbase+iMSGID1)<<16; - id3=get_reg(msgbase+iMSGID0)<<24; + id0=(*read_reg)(msgbase+iMSGID3); + id1=(*read_reg)(msgbase+iMSGID2)<<8; + id2=(*read_reg)(msgbase+iMSGID1)<<16; + id3=(*read_reg)(msgbase+iMSGID0)<<24; message_id=(id0|id1|id2|id3)>>3; } else { - id0=get_reg(msgbase+iMSGID1); - id1=get_reg(msgbase+iMSGID0)<<8; + id0=(*read_reg)(msgbase+iMSGID1); + id1=(*read_reg)(msgbase+iMSGID0)<<8; message_id=(id0|id1)>>5; } @@ -167,32 +186,38 @@ void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs) } spin_unlock(&hardware_p->rtr_lock); if ((rtr_search!=NULL) && (rtr_search->id==message_id)) - i82527_irq_rtr_handler(); + i82527_irq_rtr_handler(chip, msgobj, rtr_search, message_id); else - i82527_irq_read_handler(); + i82527_irq_read_handler(chip, msgobj, message_id); } if ( (chip->flags & SEGMENTED) != 0) - irq_register=get_reg(chip->chip_base_addr+iIRQ+SPACING); + irq_register=can_read_reg(chip, iIRQ+SPACING); else - irq_register=get_reg(chip->chip_base_addr+iIRQ); + irq_register=can_read_reg(chip, iIRQ); } } -void i82527_irq_rtr_handler(void) +void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *msgobj, + struct rtr_id *rtr_search, unsigned long message_id) { short int i=0; - - put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0); - put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1); + unsigned long msgbase=msgobj->obj_base_addr; + void (*write_reg)(unsigned char data, unsigned long address); + unsigned (*read_reg)(unsigned long address); + write_reg=chip->hostdevice->hwspecops->write_register; + read_reg=chip->hostdevice->hwspecops->read_register; + + (*write_reg)((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0); + (*write_reg)((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1); spin_lock(&hardware_p->rtr_lock); rtr_search->rtr_message->id=message_id; - rtr_search->rtr_message->length=(get_reg(msgbase + iMSGCFG) & 0xf0)>>4; + rtr_search->rtr_message->length=((*read_reg)(msgbase + iMSGCFG) & 0xf0)>>4; for (i=0; irtr_message->length; i++) - rtr_search->rtr_message->data[i]=get_reg(msgbase+iMSGDAT0+i); + rtr_search->rtr_message->data[i]=(*read_reg)(msgbase+iMSGDAT0+i); spin_unlock(&hardware_p->rtr_lock); @@ -202,33 +227,32 @@ void i82527_irq_rtr_handler(void) void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { - chip=(struct chip_t *)dev_id; - device=(struct candevice_t *)chip->hostdevice; - - put_reg=device->hwspecops->write_register; - get_reg=device->hwspecops->read_register; + unsigned irq_register; + struct chip_t *chip=(struct chip_t *)dev_id; + struct msgobj_t *msgobj; + struct canfifo_t *fifo; - irq_register=get_reg(chip->chip_base_addr+SJAIR); + irq_register=can_read_reg(chip, SJAIR); // DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); // DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n", -// get_reg(chip->chip_base_addr+SJASR)); +// can_read_reg(chip, SJASR)); if ((irq_register & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) return; - fifo=chip->msgobj[0]->fifo; - msgbase=chip->msgobj[0]->obj_base_addr; + msgobj=chip->msgobj[0]; + fifo=msgobj->fifo; if ((irq_register & IR_RI) != 0) - sja1000_irq_read_handler(); + sja1000_irq_read_handler(chip, msgobj); if ((irq_register & IR_TI) != 0) - sja1000_irq_write_handler(); + sja1000_irq_write_handler(chip, msgobj); if ((irq_register & (IR_EI|IR_DOI)) != 0) { // Some error happened // FIXME: chip should be brought to usable state. Transmission cancelled if in progress. // Reset flag set to 0 if chip is already off the bus. Full state report CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", - get_reg(chip->chip_base_addr+SJASR), irq_register); + can_read_reg(chip, SJASR), irq_register); chip->msgobj[0]->ret=-1; if (waitqueue_active(&fifo->writeq)) wake_up_interruptible(&fifo->writeq); @@ -238,61 +262,66 @@ void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs) return; } -void sja1000_irq_read_handler(void) + +void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *msgobj) { - int i=0, id=0, tmp=1; + int i=0, id=0; + struct canfifo_t *fifo=msgobj->fifo; - while (tmp) { - id = get_reg(msgbase+SJARXID0) | (get_reg(msgbase+SJARXID1)<<8); - fifo->buf_rx_entry[fifo->head].length = id & 0x0f; - fifo->buf_rx_entry[fifo->head].flags = id&ID0_RTR ? MSG_RTR : 0; - fifo->buf_rx_entry[fifo->head].timestamp = 0; - fifo->buf_rx_entry[fifo->head].cob = 0; - fifo->buf_rx_entry[fifo->head].id = id>>5; + do { + id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); + fifo->rx_writep->length = id & 0x0f; + fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0; + fifo->rx_writep->timestamp = 0; + fifo->rx_writep->cob = 0; + fifo->rx_writep->id = id>>5; - for (i=0; ibuf_rx_entry[fifo->head].length; i++) - fifo->buf_rx_entry[fifo->head].data[i]=get_reg(msgbase + - SJARXDAT0 + i); + for (i=0; irx_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); +} diff --git a/lincan/src/main.c b/lincan/src/main.c index 4ff1523..f21e78f 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -22,10 +22,12 @@ #include #include #include +#include #include #include +#include -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) #include #else #include @@ -34,10 +36,14 @@ #if !defined (__GENKSYMS__) #if (defined (MODVERSIONS) && !defined(NOVER)) #include -#include "../include/main.ver" +/*#include "../include/main.ver"*/ #endif #endif +#ifdef CONFIG_DEVFS_FS +#include +#endif + #include "../include/main.h" #include "../include/modparms.h" #include "../include/setup.h" @@ -45,6 +51,7 @@ #include "../include/open.h" #include "../include/close.h" #include "../include/read.h" +#include "../include/select.h" #include "../include/irq.h" #include "../include/ioctl.h" #include "../include/write.h" @@ -55,7 +62,8 @@ int major=CAN_MAJOR; MODULE_PARM(major,"1i"); int minor[MAX_TOT_CHIPS]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; -MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i"); +/*MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i");*/ +MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i"); int extended=0; MODULE_PARM(extended,"1i"); int pelican=0; @@ -75,26 +83,40 @@ MODULE_PARM(extmask, "1i"); int mo15mask=0; MODULE_PARM(mo15mask, "1i"); +/* Other module attributes */ +#ifdef MODULE_SUPPORTED_DEVICE +MODULE_SUPPORTED_DEVICE("can"); +#endif +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +#ifdef MODULE_DESCRIPTION +MODULE_DESCRIPTION("Universal Linux CAN-bus device driver"); +#endif + /* Global structures, used to describe the installed hardware. */ struct canhardware_t canhardware; struct canhardware_t *hardware_p=&canhardware; struct candevice_t *candevices_p[MAX_HW_CARDS]; struct chip_t *chips_p[MAX_TOT_CHIPS]; struct msgobj_t *objects_p[MAX_TOT_MSGOBJS]; +#ifdef CONFIG_DEVFS_FS +devfs_handle_t devfs_handles[MAX_TOT_MSGOBJS]; +#endif /* Pointers to dynamically allocated memory are maintained in a linked list * to ease memory deallocation. */ struct mem_addr *mem_head=NULL; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) struct file_operations can_fops= { NULL, /* llseek */ read: can_read, write: can_write, NULL, /* readdir */ - NULL, /* poll */ + poll: can_poll, ioctl: can_ioctl, NULL, /* mmap */ open: can_open, @@ -108,6 +130,7 @@ struct file_operations can_fops= owner: THIS_MODULE, read: can_read, write: can_write, + poll: can_poll, ioctl: can_ioctl, open: can_open, release: can_close, @@ -146,6 +169,9 @@ int init_module(void) goto reset_error; } + spin_lock_init(&hardware_p->rtr_lock); + hardware_p->rtr_queue=NULL; + i=0; while ( (chips_p[i] != NULL) && (i < MAX_TOT_CHIPS) ) { if (!strcmp(chips_p[i]->chip_type,"i82527")) { @@ -171,14 +197,26 @@ int init_module(void) goto interrupt_error; } - spin_lock_init(&hardware_p->rtr_lock); - hardware_p->rtr_queue=NULL; - #ifdef CONFIG_PROC_FS if (can_init_procdir()) goto proc_error; #endif +#ifdef CONFIG_DEVFS_FS + { + char dev_name[32]; + int dev_minor; + for(i=0;iminor; + sprintf (dev_name, "can%d", dev_minor); + devfs_handles[i]=devfs_register(NULL, dev_name, + DEVFS_FL_DEFAULT, major, dev_minor, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + &can_fops, (void*)objects_p[i]); + } + } +#endif return 0; #ifdef CONFIG_PROC_FS @@ -218,6 +256,13 @@ void cleanup_module(void) CANMSG("Error unregistering /proc/can entry.\n"); #endif +#ifdef CONFIG_DEVFS_FS + for(i=0;ichip_irq, chips_p[i]); i++; diff --git a/lincan/src/modparms.c b/lincan/src/modparms.c index 6f9a0de..cf4a325 100644 --- a/lincan/src/modparms.c +++ b/lincan/src/modparms.c @@ -15,42 +15,49 @@ #include #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 @@ -70,37 +77,41 @@ int parse_mod_parms(void) } while ( (hw[i] != NULL) && (i < MAX_HW_CARDS) ) { - if ( !strcmp(hw[i],"pip5") && PIP ) + if ( !strcmp(hw[i],"pip5") && ENABLE_CARD_pip ) irq_needed++; - else if (!strcmp(hw[i],"pip6") && PIP) + else if (!strcmp(hw[i],"pip6") && ENABLE_CARD_pip) irq_needed++; - else if (!strcmp(hw[i],"smartcan") && SMARTCAN) + else if (!strcmp(hw[i],"smartcan") && ENABLE_CARD_smartcan) irq_needed++; - else if (!strcmp(hw[i],"pccan-q") && PCCAN) + else if (!strcmp(hw[i],"pccan-q") && ENABLE_CARD_pccan) irq_needed=irq_needed+4; - else if (!strcmp(hw[i],"pccan-f") && PCCAN) + else if (!strcmp(hw[i],"pccan-f") && ENABLE_CARD_pccan) irq_needed++; - else if (!strcmp(hw[i],"pccan-s") && PCCAN) + else if (!strcmp(hw[i],"pccan-s") && ENABLE_CARD_pccan) irq_needed++; - else if (!strcmp(hw[i],"pccan-d") && PCCAN) + else if (!strcmp(hw[i],"pccan-d") && ENABLE_CARD_pccan) irq_needed=irq_needed+2; - else if (!strcmp(hw[i],"nsican") && NSI) + else if (!strcmp(hw[i],"nsican") && ENABLE_CARD_nsi) irq_needed++; - else if (!strcmp(hw[i],"cc104") && CC104) + else if (!strcmp(hw[i],"cc104") && ENABLE_CARD_cc_can104) irq_needed++; - else if (!strcmp(hw[i],"aim104") && AIM104) + else if (!strcmp(hw[i],"aim104") && ENABLE_CARD_aim104) irq_needed++; - else if (!strcmp(hw[i],"pc-i03") && PCI03) + else if (!strcmp(hw[i],"pc-i03") && ENABLE_CARD_pc_i03) irq_needed++; - else if (!strcmp(hw[i],"pcm3680") && PCM3680) + else if (!strcmp(hw[i],"pcm3680") && ENABLE_CARD_pcm3680) irq_needed=irq_needed+2; - else if (!strcmp(hw[i],"m437") && M437) + else if (!strcmp(hw[i],"m437") && ENABLE_CARD_m437) irq_needed++; - else if (!strcmp(hw[i],"pcccan") && PCCCAN) + else if (!strcmp(hw[i],"pcccan") && ENABLE_CARD_pcccan) irq_needed++; - else if (!strcmp(hw[i],"ssv") && SSV) + else if (!strcmp(hw[i],"ssv") && ENABLE_CARD_ssv) irq_needed=irq_needed+2; - else if (!strcmp(hw[i],"template") && TEMPLATE); + else if (!strcmp(hw[i],"bfadcan") && ENABLE_CARD_bfadcan) + irq_needed++; + else if (!strcmp(hw[i],"pikronisa") && ENABLE_CARD_pikronisa) + irq_needed++; + else if (!strcmp(hw[i],"template") && ENABLE_CARD_template); else { CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",hw[i]); return -EINVAL; @@ -122,7 +133,7 @@ int parse_mod_parms(void) while ( (irq[irq_supplied] != -1) & (irq_supplied +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) #include +#else +#include +#endif #include #include "../include/main.h" @@ -78,7 +83,7 @@ int can_open(struct inode *inode, struct file *file) fifo->rx_size = MAX_BUF_LENGTH * sizeof(struct canmsg_t); fifo->tx_size = fifo->rx_size; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) init_waitqueue(&fifo->readq); init_waitqueue(&fifo->writeq); #else @@ -89,12 +94,13 @@ int can_open(struct inode *inode, struct file *file) fifo->rx_in_progress = 0; fifo->tx_in_progress = 0; - fifo->head = fifo->tail = 0; //TEMP!! + chip->flags |= BUFFERS_ALLOCATED; if (chip->chipspecops->pre_read_config(chip,obj)<0) CANMSG("Error initializing chip for receiving\n"); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,50)) MOD_INC_USE_COUNT; - +#endif return 0; } diff --git a/lincan/src/pc_i03.c b/lincan/src/pc_i03.c new file mode 100644 index 0000000..bf64ff6 --- /dev/null +++ b/lincan/src/pc_i03.c @@ -0,0 +1,300 @@ +/* pc-i03.c + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wnadoo.nl + * This software is released under the GPL-License. + * Version 0.7 6 Aug 2001 + */ + +#include +#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) +#define MODVERSIONS +#endif + +#if defined (MODVERSIONS) +#include +#endif + +#include +#include +#include +#include + +#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; +} diff --git a/lincan/src/pcm3680.c b/lincan/src/pcm3680.c index cfb816a..853986a 100644 --- a/lincan/src/pcm3680.c +++ b/lincan/src/pcm3680.c @@ -24,18 +24,26 @@ #include "../include/i82527.h" #include "../include/sja1000p.h" +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) /* may need correction */ + #ifndef request_mem_region + #define request_mem_region(start,size,dev) (1) + #define release_mem_region(start,size) + #endif /*request_mem_region*/ +#endif /* 2.4.0 */ + /* Basic hardware io address. This is also stored in the hardware structure but * we need it global, else we have to change many internal functions. * pcm3680_base_addr is initialized in pcm3680_init_chip_data(). */ -unsigned int pcm3680_base_addr; +unsigned long pcm3680_base_addr; +static unsigned long isa_base = 0L; /* * IO_RANGE is the io-memory range that gets reserved, please adjust according * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. */ -#define IO_RANGE 0x200 +#define IO_RANGE 0x400 /** * template_request_io: - reserve io memory @@ -53,14 +61,20 @@ unsigned int pcm3680_base_addr; */ int pcm3680_request_io(unsigned long io_addr) { - if (check_region(io_addr,IO_RANGE)) { - CANMSG("Unable to open port: 0x%lx\n",io_addr); + unsigned long remap_addr; + if (!request_mem_region(io_addr,IO_RANGE,DEVICE_NAME " - pcm3680")) { + CANMSG("Unable to request IO-memory: 0x%lx\n",io_addr); return -ENODEV; } - else { - request_region(io_addr,IO_RANGE,DEVICE_NAME); - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); + if ( !( remap_addr = (long) ioremap( io_addr, IO_RANGE ) ) ) { + CANMSG("Unable to access I/O memory at: 0x%lx\n", io_addr); + release_mem_region(io_addr,IO_RANGE); + return -ENODEV; + } + isa_base=remap_addr-io_addr; + + DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", io_addr, io_addr + IO_RANGE - 1); return 0; } @@ -78,8 +92,8 @@ int pcm3680_request_io(unsigned long io_addr) */ int pcm3680_release_io(unsigned long io_addr) { - release_region(io_addr,IO_RANGE); - + iounmap((void*)isa_base); + release_mem_region(io_addr,IO_RANGE); return 0; } @@ -95,54 +109,36 @@ int pcm3680_release_io(unsigned long io_addr) */ int pcm3680_reset(int card) { -// int i=0; - -// DEBUGMSG("Resetting pcm3680 hardware ...\n"); -// pcm3680_write_register(0x01, candevices_p[card]->io_addr + -// 0x100); // Write arbitrary data to reset mem -// pcm3680_write_register(0x01, candevices_p[card]->io_addr + -// 0x300); // Write arbitrary data to reset mem -// udelay(20000); - -// pcm3680_write_register(0x00, candevices_p[card]->io_addr + SJACR); -// pcm3680_write_register(0x00, candevices_p[card]->io_addr + SJACR+0x200); - - /* Check hardware reset status chip 0 */ -/* i=0; - while ( (pcm3680_read_register(candevices_p[card]->io_addr + SJACR) - & CR_RR) && (i<=15) ) { - udelay(20000); - i++; - } - if (i>=15) { - CANMSG("Reset status timeout!\n"); - CANMSG("Please check your hardware.\n"); - return -ENODEV; - } - else - DEBUGMSG("Chip[0] reset status ok.\n"); -*/ - /* Check hardware reset status chip 1 */ -/* i=0; - while ( (pcm3680_read_register( candevices_p[card]->io_addr + SJACR + - 0x200) & CR_RR) && (i<=15) ) { - udelay(20000); - i++; - } - if (i>=15) { - CANMSG("Reset status timeout!\n"); - CANMSG("Please check your hardware.\n"); - return -ENODEV; + int i=0; + struct chip_t *chip; + int chipnr; + + DEBUGMSG("Resetting pcm3680 hardware ...\n"); + for(chipnr=0;chipnrnr_sja1000_chips;chipnr++) { + chip=candevices_p[card]->chip[chipnr]; + pcm3680_write_register(MOD_RM, chip->chip_base_addr+SJAMOD); + udelay(1000); + pcm3680_write_register(0x00, chip->chip_base_addr + SJAIER); + /* Write arbitrary data to reset chip */ + pcm3680_write_register(0x01, chip->chip_base_addr + 0x100); + udelay(1000); + i=20; + while (pcm3680_read_register(chip->chip_base_addr+SJAMOD)&MOD_RM){ + if(!i--) return -ENODEV; + udelay(1000); + pcm3680_write_register(0, chip->chip_base_addr+SJAMOD); + } + udelay(1000); + pcm3680_write_register(CDR_PELICAN, chip->chip_base_addr+SJACDR); + pcm3680_write_register(0x00, chip->chip_base_addr + SJAIER); } - else - DEBUGMSG("Chip[1] reset status ok.\n"); -*/ + return 0; } #define RESET_ADDR 0x100 #define NR_82527 0 -#define NR_SJA1000 1 +#define NR_SJA1000 2 /** * template_init_hw_data - Initialze hardware cards @@ -202,7 +198,8 @@ int pcm3680_init_chip_data(int card, int chipnr) { pcm3680_base_addr = candevices_p[card]->io_addr; candevices_p[card]->chip[chipnr]->chip_type=CHIP_TYPE; - candevices_p[card]->chip[chipnr]->chip_base_addr=candevices_p[card]->io_addr; + candevices_p[card]->chip[chipnr]->chip_base_addr= + candevices_p[card]->io_addr + 0x200*chipnr; candevices_p[card]->chip[chipnr]->clock = 16000000; candevices_p[card]->chip[chipnr]->int_clk_reg = 0x0; candevices_p[card]->chip[chipnr]->int_bus_reg = 0x0; @@ -268,7 +265,7 @@ int pcm3680_program_irq(int card) */ void pcm3680_write_register(unsigned char data, unsigned long address) { - writeb(data,address); + writeb(data,isa_base+address); } /** @@ -283,7 +280,7 @@ void pcm3680_write_register(unsigned char data, unsigned long address) */ unsigned pcm3680_read_register(unsigned long address) { - return readb(address); + return readb(isa_base+address); } /* !!! Don't change this function !!! */ diff --git a/lincan/src/pikronisa.c b/lincan/src/pikronisa.c new file mode 100644 index 0000000..104cbbc --- /dev/null +++ b/lincan/src/pikronisa.c @@ -0,0 +1,288 @@ +/* pikronisa.c + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * This software is released under the GPL-License. + * Version 0.7 6 Aug 2001 + */ + +#include +#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) +#define MODVERSIONS +#endif + +#if defined (MODVERSIONS) +#include +#endif + +#include +#include +#include +#include + +#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; +} diff --git a/lincan/src/pip.c b/lincan/src/pip.c index 09f0ae4..6bbfd8d 100644 --- a/lincan/src/pip.c +++ b/lincan/src/pip.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/lincan/src/proc.c b/lincan/src/proc.c index 401148e..79309e0 100644 --- a/lincan/src/proc.c +++ b/lincan/src/proc.c @@ -17,8 +17,13 @@ #include #endif +#include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) #include +#else +#include +#endif #include #include @@ -31,7 +36,7 @@ int remove_channel_from_procdir(void); int add_object_to_procdir(void); int remove_object_from_procdir(void); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) static int candev_readlink(struct proc_dir_entry *de, char *page); #endif @@ -45,7 +50,7 @@ struct canproc_t *base=&can_proc_base; /* The following functions are needed only for kernel version 2.2. Kernel * version 2.4 already defines them for us. */ -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) static void can_fill_inode(struct inode *inode, int fill) { if (fill) @@ -96,7 +101,7 @@ int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *par */ int can_init_procdir(void) { -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) base->can_proc_entry = new_can_proc_entry(0, "can", S_IFDIR | S_IRUGO | S_IXUGO, 0, &proc_root); #else @@ -118,7 +123,7 @@ int can_delete_procdir(void) { if (remove_channel_from_procdir()) return -ENODEV; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) return -ENODEV; #else @@ -144,7 +149,7 @@ int add_channel_to_procdir(void) sprintf(base->channel[cc]->ch_name, "channel%d",cc); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) base->channel[cc]->ch_entry = new_can_proc_entry(0, base->channel[cc]->ch_name, S_IFDIR | S_IRUGO | S_IXUGO, 0, @@ -171,7 +176,7 @@ int remove_channel_from_procdir(void) while (cc != 0) { cc--; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) if (can_remove_proc_entry(base->channel[cc]->ch_entry, base->can_proc_entry)) return -ENODEV; @@ -210,7 +215,7 @@ int add_object_to_procdir(void) sprintf(base->channel[cc]->object[i]->obj_name,"object%d",i); sprintf(base->channel[cc]->object[i]->lnk_name,"dev"); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) base->channel[cc]->object[i]->obj_entry=new_can_proc_entry( 0, base->channel[cc]->object[i]->obj_name, S_IFDIR | S_IRUGO | S_IXUGO, 0, @@ -258,7 +263,7 @@ int remove_object_from_procdir(void) obj=1; for (i=0; ichannel[cc]->object[i]->lnk, base->channel[cc]->object[i]->obj_entry)) return -ENODEV; @@ -277,7 +282,7 @@ int remove_object_from_procdir(void) return 0; } -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) static int candev_readlink(struct proc_dir_entry *de, char *page) { int i=0, nchip=0, nobj=0; diff --git a/lincan/src/read.c b/lincan/src/read.c index 4e02801..1111401 100644 --- a/lincan/src/read.c +++ b/lincan/src/read.c @@ -5,6 +5,9 @@ * Version 0.7 6 Aug 2001 */ +#define __NO_VERSION__ +#include + #include #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) #define MODVERSIONS @@ -14,7 +17,12 @@ #include #endif +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) #include +#else +#include +#endif #include #include #include @@ -45,8 +53,8 @@ inline ssize_t can_std_read(struct file *file, struct canfifo_t *fifo, return -EINTR; } if (!can_timeout) { - DEBUGMSG("Rx timeout\n"); - return -EIO; + DEBUGMSG("no data received\n"); + return 0; } if (obj->ret < 0) return obj->ret; @@ -62,14 +70,24 @@ inline ssize_t can_std_read(struct file *file, struct canfifo_t *fifo, bytes_to_copy = (length < bytes_avail) ? length : bytes_avail; ret = bytes_to_copy; + /* printk(KERN_CRIT "can RxFIFO b:%x e:%x bs:%x msg:%x rp:%x wp:%x btc:%x\n", + fifo->buf_rx_entry, fifo->buf_rx_entry+MAX_BUF_LENGTH, + fifo->rx_size, sizeof(struct canmsg_t), + fifo->rx_readp, fifo->rx_writep, bytes_to_copy); */ + + /* Copy the data to user space */ while (bytes_to_copy > 0) { + + copy_to_user(buffer, fifo->rx_readp, sizeof(struct canmsg_t)); buffer += sizeof(struct canmsg_t); bytes_to_copy -= sizeof(struct canmsg_t); fifo->rx_readp++; if (fifo->rx_readp >= fifo->buf_rx_entry + MAX_BUF_LENGTH) fifo->rx_readp = fifo->buf_rx_entry; + + /* printk(KERN_CRIT "can RxFIFO rp%x\n",fifo->rx_readp); */ } return ret; @@ -101,7 +119,7 @@ inline ssize_t can_rtr_read(struct chip_t *chip, struct msgobj_t *obj, new_rtr_entry=(struct rtr_id *)kmalloc(sizeof(struct rtr_id),GFP_ATOMIC); rtr_current->next=new_rtr_entry; } -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19)) +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)) init_waitqueue(&new_rtr_entry->rtr_wq); #else init_waitqueue_head(&new_rtr_entry->rtr_wq); diff --git a/lincan/src/select.c b/lincan/src/select.c new file mode 100644 index 0000000..27b2d22 --- /dev/null +++ b/lincan/src/select.c @@ -0,0 +1,56 @@ +/* select.c + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * This software is released under the GPL-License. + * Version 0.7.1-pi2 15 Nov 2002 + * + * added by Pavel Pisa pisa@cmp.felk.cvut.cz + */ + +#include +#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) +#define MODVERSIONS +#endif + +#if defined (MODVERSIONS) +#include +#endif + +#include +#include + +#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; +} diff --git a/lincan/src/setup.c b/lincan/src/setup.c index 74ba10f..a8f76cc 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -5,6 +5,9 @@ * Version 0.7 6 Aug 2001 */ +#define __NO_VERSION__ +#include + #include #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) #define MODVERSIONS @@ -14,10 +17,15 @@ #include #endif +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) #include +#else +#include +#endif #include -#include "../.support" +#include ".supported_cards.h" #include "../include/main.h" #include "../include/setup.h" @@ -49,6 +57,8 @@ extern int pcm3680_register(struct hwspecops_t *hwspecops); extern int aim104_register(struct hwspecops_t *hwspecops); extern int pcccan_register(struct hwspecops_t *hwspecops); extern int ssv_register(struct hwspecops_t *hwspecops); +extern int bfadcan_register(struct hwspecops_t *hwspecops); +extern int pikronisa_register(struct hwspecops_t *hwspecops); int init_device_struct(int card); int init_hwspecops(int card); @@ -86,7 +96,12 @@ int del_mem_from_list(void *address_p) DEBUGMSG("del_mem_from_list %p, mem_head=%p\n", address_p, mem_head); return 0; #endif - + if(mem_head == NULL) { + CANMSG("del_mem_from_list: mem_head == NULL address_p=%p!\n", + address_p); + return 0; + } + mem_search = mem_head; if (mem_head->address == address_p) { @@ -114,6 +129,10 @@ int del_mem_list(void) DEBUGMSG("del_mem_list, mem_head=%p\n", mem_head); return 0; #endif + if(mem_head == NULL) { + CANMSG("del_mem_list: mem_head == NULL!\n"); + return 0; + } while (mem_head->next != NULL) { mem_old=mem_head; @@ -271,12 +290,12 @@ int init_obj_struct(int card, int chip) int init_hwspecops(int card) { - #ifdef TEMPLATE + #ifdef ENABLE_CARD_template if (!strcmp(candevices_p[card]->hwname,"template")) { template_register(candevices_p[card]->hwspecops); } #endif - #ifdef PIP + #ifdef ENABLE_CARD_pip if (!strcmp(candevices_p[card]->hwname,"pip5")) { pip5_register(candevices_p[card]->hwspecops); } @@ -284,37 +303,37 @@ int init_hwspecops(int card) pip6_register(candevices_p[card]->hwspecops); } #endif - #ifdef SMARTCAN + #ifdef ENABLE_CARD_smartcan if (!strcmp(candevices_p[card]->hwname,"smartcan")) { smartcan_register(candevices_p[card]->hwspecops); } #endif - #ifdef NSI + #ifdef ENABLE_CARD_nsi if (!strcmp(candevices_p[card]->hwname,"nsican")) { nsi_register(candevices_p[card]->hwspecops); } #endif - #ifdef CC104 + #ifdef ENABLE_CARD_cc_can104 if (!strcmp(candevices_p[card]->hwname,"cc104")) { cc104_register(candevices_p[card]->hwspecops); } #endif - #ifdef AIM104 + #ifdef ENABLE_CARD_aim104 if (!strcmp(candevices_p[card]->hwname,"aim104")) { aim104_register(candevices_p[card]->hwspecops); } #endif - #ifdef PCI03 + #ifdef ENABLE_CARD_pc_i03 if (!strcmp(candevices_p[card]->hwname,"pc-i03")) { pci03_register(candevices_p[card]->hwspecops); } #endif - #ifdef PCM3680 + #ifdef ENABLE_CARD_pcm3680 if (!strcmp(candevices_p[card]->hwname,"pcm3680")) { pcm3680_register(candevices_p[card]->hwspecops); } #endif - #ifdef PCCAN + #ifdef ENABLE_CARD_pccan if (!strcmp(candevices_p[card]->hwname,"pccan-f") | !strcmp(candevices_p[card]->hwname,"pccan-s") ) { pccanf_register(candevices_p[card]->hwspecops); @@ -326,21 +345,31 @@ int init_hwspecops(int card) pccanq_register(candevices_p[card]->hwspecops); } #endif - #ifdef M437 + #ifdef ENABLE_CARD_m437 if (!strcmp(candevices_p[card]->hwname,"m437")) { m437_register(candevices_p[card]->hwspecops); } #endif - #ifdef PCCCAN + #ifdef ENABLE_CARD_pcccan if (!strcmp(candevices_p[card]->hwname,"pcccan")) { pcccan_register(candevices_p[card]->hwspecops); } #endif - #ifdef SSV + #ifdef ENABLE_CARD_ssv if (!strcmp(candevices_p[card]->hwname,"ssv")) { ssv_register(candevices_p[card]->hwspecops); } #endif + #ifdef ENABLE_CARD_bfadcan + if (!strcmp(candevices_p[card]->hwname,"bfadcan")) { + bfadcan_register(candevices_p[card]->hwspecops); + } + #endif + #ifdef ENABLE_CARD_pikronisa + if (!strcmp(candevices_p[card]->hwname,"pikronisa")) { + pikronisa_register(candevices_p[card]->hwspecops); + } + #endif return 0; } diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index e1da4c1..0955c76 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -210,22 +210,22 @@ int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) // TODO: this would be best sja1000_irq_read_handler(chip); // now just duplicate the code. do { - id=(can_read_reg(chip, SJARXID1)<<8) + can_read_reg(chip, - SJARXID0); - fifo->buf_rx_entry[fifo->head].length = (id>>8) & 0x0f; - fifo->buf_rx_entry[fifo->head].id = id>>5; - fifo->buf_rx_entry[fifo->head].flags = id&ID0_RTR ? - MSG_RTR : 0; - fifo->buf_rx_entry[fifo->head].timestamp = 0; - fifo->buf_rx_entry[fifo->head].cob = 0; - for (i=0; ibuf_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; irx_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 diff --git a/lincan/src/sja1000p.c b/lincan/src/sja1000p.c index f95f1a7..deb1c89 100644 --- a/lincan/src/sja1000p.c +++ b/lincan/src/sja1000p.c @@ -23,14 +23,6 @@ #include "../include/main.h" #include "../include/sja1000p.h" -struct chip_t *chip_irq=NULL; -struct candevice_t *device_irq=NULL; -struct canfifo_t *fifo_irq=NULL; -void (*put_reg)(unsigned char data, unsigned long address); -unsigned (*get_reg)(unsigned long address); - - - int sja1000p_enable_configuration(struct chip_t *chip) { int i=0; @@ -41,8 +33,8 @@ int sja1000p_enable_configuration(struct chip_t *chip) flags=can_read_reg(chip,SJAMOD); while ((!(flags & MOD_RM)) && (i<=10)) { - can_write_reg(chip, MOD_RM, SJAMOD); -// TODO: chinfigurable MOD_AFM (32/16 bit acceptance filter) + can_write_reg(chip, MOD_RM, SJAMOD); +// TODO: configurable MOD_AFM (32/16 bit acceptance filter) // config MOD_LOM (listen only) udelay(100); i++; @@ -64,9 +56,10 @@ int sja1000p_disable_configuration(struct chip_t *chip) flags=can_read_reg(chip,SJAMOD); - while ( (flags & MOD_RM) && (i<=10) ) { + while ( (flags & MOD_RM) && (i<=50) ) { +// could be as long as 11*128 bit times after buss-off can_write_reg(chip, 0, SJAMOD); -// TODO: chinfigurable MOD_AFM (32/16 bit acceptance filter) +// TODO: configurable MOD_AFM (32/16 bit acceptance filter) // config MOD_LOM (listen only) udelay(100); i++; @@ -203,39 +196,53 @@ void sja1000p_read(struct chip_t *chip, struct canfifo_t *fifo) { do { flags = can_read_reg(chip,SJAFRM); if(flags&FRM_FF) { - fifo->buf_rx_entry[fifo->head].id = + fifo->rx_writep->id = (can_read_reg(chip,SJAID0)<<21) + (can_read_reg(chip,SJAID1)<<13) + (can_read_reg(chip,SJAID2)<<5) + (can_read_reg(chip,SJAID3)>>3); datastart = SJADATE; } else { - fifo->buf_rx_entry[fifo->head].id = + fifo->rx_writep->id = (can_read_reg(chip,SJAID0)<<3) + (can_read_reg(chip,SJAID1)>>5); datastart = SJADATS; } - fifo->buf_rx_entry[fifo->head].flags = + fifo->rx_writep->flags = ((flags & FRM_RTR) ? MSG_RTR : 0) | ((flags & FRM_FF) ? MSG_EXT : 0); len = flags & FRM_DLC_M; for(i=0; i< len; i++) { - fifo->buf_rx_entry[fifo->head].data[i]= - can_read_reg(chip,datastart+i); + fifo->rx_writep->data[i]=can_read_reg(chip,datastart+i); } - fifo->buf_rx_entry[fifo->head].length = len; - fifo->head++; fifo->head %= MAX_BUF_LENGTH; -// FIXME: what if fifo->head == fifo->tail again ? + fifo->rx_writep->length = len; + + fifo->rx_writep++; + if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) + fifo->rx_writep = fifo->buf_rx_entry; + +// FIXME: what if fifo->rx_writep == fifo->rx_readp again ? + can_write_reg(chip, CMR_RRB, SJACMR); } while (can_read_reg(chip, SJASR) & SR_RBS); } int sja1000p_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) { - int i; - i=can_read_reg(chip,SJASR); + int status; + status=can_read_reg(chip,SJASR); - if (!(i&SR_RBS)) { + if(status & SR_BS) { + /* Try to recover from error condition */ + DEBUGMSG("sja1000p_pre_read_config bus-off recover 0x%x\n",status); + sja1000p_enable_configuration(chip); + can_write_reg(chip, 0, SJARXERR); + can_write_reg(chip, 0, SJATXERR1); + can_read_reg(chip, SJAECC); + sja1000p_disable_configuration(chip); + } + + if (!(status&SR_RBS)) { return 0; } @@ -251,13 +258,23 @@ int sja1000p_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, { int i=0; unsigned int id; + int status; /* Wait until Transmit Buffer Status is released */ - while ( !(can_read_reg(chip, SJASR) & SR_TBS) && + while ( !((status=can_read_reg(chip, SJASR)) & SR_TBS) && i++data[i], SJADATE+i); } } else { - id=msg->id >> 5; - can_write_reg(chip, id & 0xff, SJAID0); - id >>= 8; + id=msg->id<<5; + can_write_reg(chip, (id >> 8) & 0xff, SJAID0); can_write_reg(chip, id & 0xff, SJAID1); for(i=0; i < msg->length; i++) { can_write_reg(chip, msg->data[i], SJADATS+i); @@ -379,47 +395,100 @@ int sja1000p_config_irqs(struct chip_t *chip, short irqs) return -ENOSYS; } -void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +void sja1000p_irq_write_handler(struct chip_t *chip, struct canfifo_t *fifo) { - int irq_register; - chip_irq=(struct chip_t *)dev_id; - device_irq=(struct candevice_t *)chip_irq->hostdevice; + fifo->tx_readp++; + if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) + fifo->tx_readp = fifo->buf_tx_entry; + if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty + fifo->tx_in_progress = 0; + if (waitqueue_active(&fifo->writeq)) { + chip->msgobj[0]->ret = 0; //CHECKME or 26? + wake_up_interruptible(&fifo->writeq); + } + return; + } + if (chip->chipspecops->pre_write_config(chip, chip->msgobj[0], + fifo->tx_readp)) { + if (waitqueue_active(&fifo->writeq)) { + chip->msgobj[0]->ret = -1; + wake_up_interruptible(&fifo->writeq); + return; + } + } + if (chip->chipspecops->send_msg(chip, chip->msgobj[0], + fifo->tx_readp)) { + if (waitqueue_active(&fifo->writeq)) { + chip->msgobj[0]->ret = -1; + wake_up_interruptible(&fifo->writeq); + return; + } + } - put_reg=device_irq->hwspecops->write_register; - get_reg=device_irq->hwspecops->read_register; +} + +#define MAX_RETR 10 - irq_register=get_reg(chip_irq->chip_base_addr+SJAIR); +void sja1000p_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_register, status, error_code; + int static retransmitted=0; /* FIXME - should go into chip struct */ + struct chip_t *chip=(struct chip_t *)dev_id; + struct canfifo_t *fifo; + + irq_register=can_read_reg(chip,SJAIR); // DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); // DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n", -// get_reg(chip_irq->chip_base_addr+SJASR)); +// can_read_reg(chip,SJASR)); if ((irq_register & (IR_BEI|IR_EPI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) return; - fifo_irq=chip_irq->msgobj[0]->fifo; + if(!chip->msgobj[0]->flags & BUFFERS_ALLOCATED) { + CANMSG("sja1000p_irq_handler: called with device closed, irq_register 0x%02x\n", irq_register); + return; + } + fifo=chip->msgobj[0]->fifo; if ((irq_register & IR_RI) != 0) { - sja1000p_read(chip_irq,fifo_irq); - chip_irq->msgobj[0]->ret = 0; - if (waitqueue_active(&fifo_irq->readq)) - wake_up_interruptible(&fifo_irq->readq); + sja1000p_read(chip,fifo); + chip->msgobj[0]->ret = 0; + if (waitqueue_active(&fifo->readq)) + wake_up_interruptible(&fifo->readq); } if ((irq_register & IR_TI) != 0) { - chip_irq->msgobj[0]->ret = 0; - if (waitqueue_active(&fifo_irq->writeq)) - wake_up_interruptible(&fifo_irq->writeq); + chip->msgobj[0]->ret = 0; + sja1000p_irq_write_handler(chip,fifo); } if ((irq_register & (IR_EI|IR_BEI|IR_EPI|IR_DOI)) != 0) { // Some error happened - CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", - get_reg(chip_irq->chip_base_addr+SJASR), irq_register); + status=can_read_reg(chip,SJASR); + error_code=can_read_reg(chip,SJAECC); + CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n", + status, irq_register, error_code); // FIXME: chip should be brought to usable state. Transmission cancelled if in progress. // Reset flag set to 0 if chip is already off the bus. Full state report - chip_irq->msgobj[0]->ret=-1; - if (waitqueue_active(&fifo_irq->writeq)) - wake_up_interruptible(&fifo_irq->writeq); - if (waitqueue_active(&fifo_irq->readq)) - wake_up_interruptible(&fifo_irq->readq); + chip->msgobj[0]->ret=-1; + + if(error_code == 0xd9) { + chip->msgobj[0]->ret= -ENXIO; + /* no such device or address - no ACK received */ + } + if(retransmitted++>MAX_RETR) { + can_write_reg(chip, CMR_AT, SJACMR); // cancel any transmition + retransmitted = 0; + } + if(status&SR_BS) { + CANMSG("bus-off, resetting sja1000p\n"); + can_write_reg(chip, 0, SJAMOD); + } + + if (waitqueue_active(&fifo->writeq)) + wake_up_interruptible(&fifo->writeq); + if (waitqueue_active(&fifo->readq)) + wake_up_interruptible(&fifo->readq); + } else { + retransmitted=0; } return; diff --git a/lincan/utils/Makefile b/lincan/utils/Makefile new file mode 100644 index 0000000..09ad302 --- /dev/null +++ b/lincan/utils/Makefile @@ -0,0 +1,40 @@ +# Makefile for the Linux CAN-bus driver. +# Written by Arnaud Westenberg email:arnaud@wanadoo.nl +# This software is released under the GPL-License. +# Version 0.7 6 Aug 2001 +# +# Changes made by Pavel Pisa pisa@cmp.felk.cvut.cz as preliminary +# study for OCERA Real Time CAN/CANOpen project ORTCAN +# +########## The following options can be changed ########## + +# Compiler +CC = gcc + +CFLAGS = -I../include -O2 + +all: default + +default: utils + +dep: + $(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M *.c $(MORE_C_FILES) > .depend + +install: + echo Nothing to install + +utils: rxtx sendburst readburst send can-proxy + +rxtx: rxtx.o + +sendburst: sendburst.o + +readburst: readburst.o + +send: send.o + +clean : + rm -f rxtx sendburst readburst send can-proxy *.o .depend + +-include .depend + diff --git a/lincan/utils/can-proxy.c b/lincan/utils/can-proxy.c new file mode 100644 index 0000000..ab9bee8 --- /dev/null +++ b/lincan/utils/can-proxy.c @@ -0,0 +1,519 @@ +//############################################################################# +/** @file can-proxy.c + @author: T.Motylewski@bfad.de + Operating System: LINUX + Compiler: gcc + Description: gateway CAN-UDP. +receives all CAN packets, prints them and may save them to a file. +may send packets with ID, len, data entered from keyboard or from text file. +may send to CAN packets received over UDP +will forward packets from CAN to the most recent IP/UDP address. +*/ +//############################################################################# + + +//----------------------------------------------------------------------------- +// INCLUDES +//----------------------------------------------------------------------------- + +#include +#include "can.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 #include #include +#include #include #include +#include #include #include "../include/can.h" int fd; +int can_fd_wait(int fd, int wait_sec) +{ + int ret; + struct timeval timeout; + fd_set set; + + FD_ZERO (&set); + FD_SET (fd, &set); + timeout.tv_sec = wait_sec; + timeout.tv_usec = 0; + while ((ret=select(FD_SETSIZE,&set, NULL, NULL,&timeout))==-1 + &&errno==-EINTR); + return ret; +} + + /*--- handler on SIGINT signal : the program quit with CTL-C ---*/ void sortie(int sig) { @@ -43,11 +61,19 @@ int main(void) readmsg.flags=0; readmsg.cob=0; readmsg.timestamp=0; + #if 1 + ret=can_fd_wait(fd, 5); + printf("can_fd_wait returnet %d\n",ret); + #endif ret=read(fd,&readmsg,sizeof(struct canmsg_t)); if(ret <0) { printf("Error reading message\n"); } + else if(ret == 0) + { + printf("No message arrived\n"); + } else { printf("Received message #%lu: id=%lX dlc=%u",i,readmsg.id,readmsg.length); diff --git a/lincan/utils/rxtx.c b/lincan/utils/rxtx.c index 0adcef1..5fe75eb 100644 --- a/lincan/utils/rxtx.c +++ b/lincan/utils/rxtx.c @@ -38,7 +38,7 @@ int main(void) remote[count]='\0'; } if (remote[0]=='y') - message.flags |= MSG_RTR; + message.flags = MSG_RTR; else message.flags = 0; // message.flags |= MSG_EXT; hard code EXT for now @@ -55,6 +55,8 @@ int main(void) specialfile[MAXL]='\0'; printf("Enter the Message ID "); scanf("%lx",&message.id); + if(message.id>=(1<<11)) + message.flags |= MSG_EXT; printf("Enter the Message Length "); scanf("%d",&message.length); for (i=0; i +#include +#include +#include +#include + +#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