Merge branch 'master' into can-usb1
authorppisa <pisa@cmp.felk.cvut.cz>
Sat, 1 Nov 2008 12:40:35 +0000 (13:40 +0100)
committerppisa <pisa@cmp.felk.cvut.cz>
Sat, 1 Nov 2008 12:40:35 +0000 (13:40 +0100)
The changes between LinCAN 0.3.3 version and current master head are propagated
into "can-usb1" branch.

Conflicts:

lincan/include/kthread.h
lincan/include/main.h
lincan/src/Makefile.omk
lincan/src/bfadcan.c
lincan/src/boardlist.c
lincan/src/finish.c
lincan/src/kthread.c
lincan/src/main.c
lincan/src/modparms.c
lincan/src/proc.c
lincan/src/setup.c

205 files changed:
build-embedded.sh [new file with mode: 0755]
embedded/Makefile [new file with mode: 0644]
embedded/Makefile.omk [new file with mode: 0644]
embedded/README.txt [new file with mode: 0644]
embedded/app/Makefile [new file with mode: 0644]
embedded/app/Makefile.omk [new file with mode: 0644]
embedded/app/usbcan/Makefile [new file with mode: 0644]
embedded/app/usbcan/Makefile.omk [new file with mode: 0644]
embedded/app/usbcan/can.c [new file with mode: 0644]
embedded/app/usbcan/can/can.h [new file with mode: 0644]
embedded/app/usbcan/can/can_queue.h [new file with mode: 0644]
embedded/app/usbcan/can/can_sysdep.h [new file with mode: 0644]
embedded/app/usbcan/can/can_sysless.h [new file with mode: 0644]
embedded/app/usbcan/can/canmsg.h [new file with mode: 0644]
embedded/app/usbcan/can/constants.h [new file with mode: 0644]
embedded/app/usbcan/can/devcommon.h [new file with mode: 0644]
embedded/app/usbcan/can/errno-base.h [new file with mode: 0755]
embedded/app/usbcan/can/errno.h [new file with mode: 0755]
embedded/app/usbcan/can/finish.h [new file with mode: 0644]
embedded/app/usbcan/can/i82527.h [new file with mode: 0644]
embedded/app/usbcan/can/main.h [new file with mode: 0644]
embedded/app/usbcan/can/modparms.h [new file with mode: 0644]
embedded/app/usbcan/can/setup.h [new file with mode: 0644]
embedded/app/usbcan/can/sja1000p.h [new file with mode: 0644]
embedded/app/usbcan/can/ul_listbase.h [new file with mode: 0644]
embedded/app/usbcan/can/ul_usb1.h [new file with mode: 0644]
embedded/app/usbcan/can_quesysless.c [new file with mode: 0644]
embedded/app/usbcan/can_queue.c [new file with mode: 0644]
embedded/app/usbcan/devcommon.c [new file with mode: 0644]
embedded/app/usbcan/finish.c [new file with mode: 0644]
embedded/app/usbcan/main.c [new file with mode: 0644]
embedded/app/usbcan/setup.c [new file with mode: 0644]
embedded/app/usbcan/sja1000p.c [new file with mode: 0644]
embedded/app/usbcan/ul_usb1.c [new file with mode: 0644]
embedded/app/usbcan/usb/usb_defs.h [new file with mode: 0644]
embedded/app/usbcan/usb/usb_vend.h [new file with mode: 0644]
embedded/app/usbcan/usb_srq.c [new file with mode: 0644]
embedded/app/usbcan/usb_vend.c [new file with mode: 0644]
embedded/arch/Makefile [new file with mode: 0644]
embedded/arch/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/Makefile [new file with mode: 0644]
embedded/arch/arm/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/generic/Makefile [new file with mode: 0644]
embedded/arch/arm/generic/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/generic/defines/Makefile [new file with mode: 0644]
embedded/arch/arm/generic/defines/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/generic/defines/cpu_def.h [new file with mode: 0644]
embedded/arch/arm/generic/defines/hal_intr.h [new file with mode: 0644]
embedded/arch/arm/generic/defines/types.h [new file with mode: 0644]
embedded/arch/arm/generic/libs/Makefile [new file with mode: 0644]
embedded/arch/arm/generic/libs/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/generic/libs/misc/Makefile [new file with mode: 0644]
embedded/arch/arm/generic/libs/misc/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/generic/libs/misc/system_stub.c [new file with mode: 0644]
embedded/arch/arm/generic/libs/misc/system_stub.h [new file with mode: 0644]
embedded/arch/arm/generic/libs/misc/undef_support.c [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/Makefile [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/LPC210x.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/LPC214x.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/LPC21xx.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/LPC22xx.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/Makefile [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/armVIC.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcADC-214x.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcADC.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcEMC.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcGPIO.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcI2C.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcPIN.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcRTC.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcSCB.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcSPI.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcTMR.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcUART.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcUSB.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcVIC.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/defines/lpcWD.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/Makefile [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/hal.c [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/hal_ints.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.c [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/hal_machperiph.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/ivt.S [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/hal/startup.S [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/Makefile.omk [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/iap.c [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/iap_asm.S [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/iap_kvpb.c [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/lpciap.h [new file with mode: 0644]
embedded/arch/arm/mach-lpc21xx/libs/iap/lpciap_kvpb.h [new file with mode: 0644]
embedded/arch/generic/Makefile [new file with mode: 0644]
embedded/arch/generic/Makefile.omk [new file with mode: 0644]
embedded/arch/generic/defines/Makefile [new file with mode: 0644]
embedded/arch/generic/defines/Makefile.omk [new file with mode: 0644]
embedded/arch/generic/defines/byteswap.h [new file with mode: 0644]
embedded/arch/generic/defines/endian.h [new file with mode: 0644]
embedded/arch/generic/defines/lt_timer.h [new file with mode: 0644]
embedded/arch/generic/defines/lt_timer_types.h [new file with mode: 0644]
embedded/board/Makefile [new file with mode: 0644]
embedded/board/Makefile.omk [new file with mode: 0644]
embedded/board/arm/Makefile [new file with mode: 0644]
embedded/board/arm/Makefile.omk [new file with mode: 0644]
embedded/board/arm/ul_usb1/Makefile [new file with mode: 0644]
embedded/board/arm/ul_usb1/Makefile.omk [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.bell-keypad [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.garage-gate [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.ha-switch [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.ha-switch-ulboot [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.u2uv2 [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.ul_usb1 [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.ulboot [new file with mode: 0644]
embedded/board/arm/ul_usb1/config/config.usbcan [new file with mode: 0644]
embedded/board/arm/ul_usb1/defines/Makefile [new file with mode: 0644]
embedded/board/arm/ul_usb1/defines/Makefile.omk [new file with mode: 0644]
embedded/board/arm/ul_usb1/defines/system_def-ha-switch.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/defines/system_def-hisc-garage-gate.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/defines/system_def-hisc-keypad.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/defines/system_def.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/Makefile [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/Makefile.omk [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/Makefile [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/Makefile.omk [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/bsp0hwinit.c [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/bspbase.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/kbd_io_hisc.c [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/uart.c [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/bspbase/uart.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/Makefile [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/Makefile.omk [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/keyval_loc.h [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-cfg [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2103.ld-flash [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-app [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-boot [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2105.ld-cfg [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-app [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-boot [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/lpc2148.ld-cfg [new file with mode: 0644]
embedded/board/arm/ul_usb1/libs/ldscripts/mem_loc.h [new file with mode: 0644]
embedded/libs4c/Makefile [new file with mode: 0644]
embedded/libs4c/Makefile.omk [new file with mode: 0644]
embedded/libs4c/i2c/Makefile [new file with mode: 0644]
embedded/libs4c/i2c/Makefile.omk [new file with mode: 0644]
embedded/libs4c/i2c/i2c_c552.c [new file with mode: 0644]
embedded/libs4c/i2c/i2c_drv.c [new file with mode: 0644]
embedded/libs4c/i2c/i2c_drv.h [new file with mode: 0644]
embedded/libs4c/kbd/Makefile [new file with mode: 0644]
embedded/libs4c/kbd/Makefile.omk [new file with mode: 0644]
embedded/libs4c/kbd/kbd.h [new file with mode: 0644]
embedded/libs4c/kbd/kbd_base.c [new file with mode: 0644]
embedded/libs4c/kbd/kbd_dev_ops.c [new file with mode: 0644]
embedded/libs4c/keyval/Makefile [new file with mode: 0644]
embedded/libs4c/keyval/Makefile.omk [new file with mode: 0644]
embedded/libs4c/keyval/keyval_id.h [new file with mode: 0644]
embedded/libs4c/keyval/keyvalpb.c [new file with mode: 0644]
embedded/libs4c/keyval/keyvalpb.h [new file with mode: 0644]
embedded/libs4c/usb/Makefile [new file with mode: 0644]
embedded/libs4c/usb/Makefile.omk [new file with mode: 0644]
embedded/libs4c/usb/base/Makefile [new file with mode: 0644]
embedded/libs4c/usb/base/Makefile.omk [new file with mode: 0644]
embedded/libs4c/usb/base/usb.c [new file with mode: 0644]
embedded/libs4c/usb/base/usb/usb.h [new file with mode: 0644]
embedded/libs4c/usb/base/usb/usb_spec.h [new file with mode: 0644]
embedded/libs4c/usb/base/usb/usb_srq.h [new file with mode: 0644]
embedded/libs4c/usb/base/usb/usbdebug.h [new file with mode: 0644]
embedded/libs4c/usb/base/usbdebug.c [new file with mode: 0644]
embedded/libs4c/usb/lpcusb/Makefile [new file with mode: 0644]
embedded/libs4c/usb/lpcusb/Makefile.omk [new file with mode: 0644]
embedded/libs4c/usb/lpcusb/lpc.c [new file with mode: 0644]
embedded/libs4c/usb/lpcusb/lpcusb.c [new file with mode: 0644]
embedded/libs4c/usb/lpcusb/usb/lpc.h [new file with mode: 0644]
embedded/libs4c/usb/lpcusb/usb/lpcusb.h [new file with mode: 0644]
embedded/libs4c/usb/more/Makefile [new file with mode: 0644]
embedded/libs4c/usb/more/Makefile.omk [new file with mode: 0644]
embedded/libs4c/usb/more/usb/msc_loader.h [new file with mode: 0644]
embedded/libs4c/usb/more/usb/usb_com.h [new file with mode: 0644]
embedded/libs4c/usb/more/usb/usb_loader.h [new file with mode: 0644]
embedded/libs4c/usb/more/usb_com.c [new file with mode: 0644]
embedded/libs4c/usb/more/usb_srq.c [new file with mode: 0644]
embedded/libs4c/usb/pdiusb/Makefile [new file with mode: 0644]
embedded/libs4c/usb/pdiusb/Makefile.omk [new file with mode: 0644]
embedded/libs4c/usb/pdiusb/pdi.c [new file with mode: 0644]
embedded/libs4c/usb/pdiusb/pdiusb.c [new file with mode: 0644]
embedded/libs4c/usb/pdiusb/usb/pdi.h [new file with mode: 0644]
embedded/libs4c/usb/pdiusb/usb/pdiusb.h [new file with mode: 0644]
lincan/include/can_sysdep.h
lincan/include/main.h
lincan/include/proc.h
lincan/include/setup.h
lincan/include/usbcan.h [new file with mode: 0644]
lincan/src/Makefile.omk
lincan/src/boardlist.c
lincan/src/finish.c
lincan/src/main.c
lincan/src/modparms.c
lincan/src/proc.c
lincan/src/setup.c
lincan/src/usbcan.c [new file with mode: 0644]
omk/rules/sysless/Makefile.rules [new file with mode: 0644]

diff --git a/build-embedded.sh b/build-embedded.sh
new file mode 100755 (executable)
index 0000000..09e10cc
--- /dev/null
@@ -0,0 +1,41 @@
+SOURCE_DIRS="embedded/app embedded/arch embedded/board embedded/libs4c"
+OMK_RULES_DIR=omk/rules/sysless
+BUILD_DIR=embedded-build/can-usb1
+OMK_CONFIG=embedded/board/arm/ul_usb1/config/config.usbcan
+
+SOURCE_PATHS+=" $SOURCE_DIRS"
+SOURCE_PATHS+=" $(echo $OMK_RULES_DIR/*)"
+
+TOP_RELATIVE="$( echo "$BUILD_DIR" | sed -n -e 's#[^/]*/[^/]*#../#pg' ).."
+
+echo "SOURCE_PATHS=$SOURCE_PATHS"
+echo "TOP_RELATIVE=$TOP_RELATIVE"
+
+mkdir -p "$BUILD_DIR" || exit 1
+
+for i in $SOURCE_PATHS ; do
+  b="$(basename $i)"
+  if [ ! -e "$BUILD_DIR/$b" ] ; then
+    echo "$BUILD_DIR : ln -s $TOP_RELATIVE/$i $b"
+    ( cd "$BUILD_DIR" && ln -s "$TOP_RELATIVE/$i" "$b" ) || exit 1
+  fi
+done
+
+for i in $SOURCE_DIRS ; do
+  b="$(basename $i)"
+  if ! grep -s "\<$b\>" "$BUILD_DIR/Makefile.omk" ; then
+    echo "SUBDIRS += $b" >>"$BUILD_DIR/Makefile.omk" || exit 1
+  fi
+done
+
+if [ ! -e "$BUILD_DIR/Makefile" ] ; then
+  cp omk/Makefile "$BUILD_DIR/Makefile"
+fi
+
+if [ ! -e "$BUILD_DIR/config.omk" ] ; then
+  ( cd "$BUILD_DIR" && ln -s "$TOP_RELATIVE/$OMK_CONFIG" config.omk )
+fi
+
+( cd "$BUILD_DIR" && make default-config ) || exit 1
+
+( cd "$BUILD_DIR" && make ) || exit 1
diff --git a/embedded/Makefile b/embedded/Makefile
new file mode 100644 (file)
index 0000000..bdb6d45
--- /dev/null
@@ -0,0 +1,15 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" == `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else   
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
+# DO NOT DELETE
diff --git a/embedded/Makefile.omk b/embedded/Makefile.omk
new file mode 100644 (file)
index 0000000..c0f9113
--- /dev/null
@@ -0,0 +1,6 @@
+# -*- makefile -*-
+
+SUBDIRS = app arch board libs4c 
+
+-include $(SOURCES_DIR)/Makefile.omk-additional 
+
diff --git a/embedded/README.txt b/embedded/README.txt
new file mode 100644 (file)
index 0000000..52b1e62
--- /dev/null
@@ -0,0 +1,93 @@
+uLan embedded source tree v 0.5
+===============================
+
+This is highly experimental code, look for latest
+version on the project related pages
+
+  http://ulan.sourceforge.net/
+  http://sourceforge.net/projects/ulan
+  http://cmp.felk.cvut.cz/~pisa#ulan
+
+To build code you need to have SDCC 2.5.3-CVS.
+The snapshot past Sep 3 2005 are OK.
+The GNU make program 3.81beta3 or better is required.
+The full build has been tested on Linux based hosts only
+for now. The uLan protocol code has been successfully build
+by Keil compiler under Windows in the past.
+
+The archive has to be unpacked with symbolic links
+for now. We are thinking about rearrangement
+of the code to make it more portable and drop
+link requirements.
+
+The MCS51 is only port provided in this version.
+
+To build do
+
+  cd ul_embedded-x.y/mcs51
+  make defaul-config
+  make
+
+You should find resulting binaries in the "_compiled/bin"
+directory. The board and application is selected by used
+"config.omk" file. Example files can be found in the "configs"
+directory.
+
+The next boards and applications are supported
+
+Device: MCS51 TI MSC-1210
+   Board: ULAD-21 - AD converter and uLan2USB converter
+   Applications:
+     config.mscboot-ulad21 - uLan enabled remote boot-loader and boot-block
+     config.u2u-ulad21     - uLan to USB converter
+
+   Board: HISC - Home Information System Controller
+     config.mscboot-hisc   - boot block for distributed HISC system
+     config.blinder        - blinder controller
+     config.kswtimer       - kettle switch timer
+   
+Device: MCS51 Atmel AT89C51RD2
+     config.u2u-ps1        - AT89C51RD2 based uLan2USB converter
+
+
+The procedure to write boot-block into ULAD-21 MSC1210 based board
+requires next steps
+
+  FLASHMSC_TTY=/dev/ttyS1
+  flashmsc -d $FLASHMSC_TTY -E 0x807f
+  flashmsc -d $FLASHMSC_TTY -E 0x7fff
+  flashmsc -d $FLASHMSC_TTY -X 18432000 ulad21-hcr.hex
+  flashmsc -d $FLASHMSC_TTY -X 18432000 ulad21-boot.hex
+
+The "flashmsc" sources can be found at page
+  http://cmp.felk.cvut.cz/~pisa/#mcuutils
+
+To replace application in the converter or other uLan node
+over uLan communication protocol, next steps are required
+
+  echo Reset application if running
+  ul_sendhex -g 0 -m 0
+  echo Waiting to target to go into boot block
+  echo If application blocks, reset device at this time
+  echo to activate boot block now
+  ul_sendhex -o 0 -m 0
+  echo Found devices
+  ul_sendhex -p 64
+  echo Erasing flash
+  ul_sendhex -m 62 -t 5 -e -s 0x2000 -l 0x6000
+  sleep 2
+  echo Loading application
+  ul_sendhex -m 62 -t 5 application.hex
+
+Look for uLan driver for host side (Linux, Windows, DOS)
+uLan protocol driver. The uLan2USB converter requires
+at least version ul_drv-0.7 release.
+
+The code authors
+
+  (C) Copyright 1996-2005 by Pavel Pisa
+        http://cmp.felk.cvut.cz/~pisa
+  (C) Copyright 1996-2005 PiKRON Ltd.
+        http://www.pikron.com
+  (C) Copyright 2002-2005 Petr Smolik
+
diff --git a/embedded/app/Makefile b/embedded/app/Makefile
new file mode 100644 (file)
index 0000000..f595272
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" == `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else   
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/embedded/app/Makefile.omk b/embedded/app/Makefile.omk
new file mode 100644 (file)
index 0000000..fd0ecae
--- /dev/null
@@ -0,0 +1,4 @@
+# -*- makefile -*-
+
+SUBDIRS = usbcan
+
diff --git a/embedded/app/usbcan/Makefile b/embedded/app/usbcan/Makefile
new file mode 100644 (file)
index 0000000..f595272
--- /dev/null
@@ -0,0 +1,14 @@
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ;  while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" == `pwd`  ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+       @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else   
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
diff --git a/embedded/app/usbcan/Makefile.omk b/embedded/app/usbcan/Makefile.omk
new file mode 100644 (file)
index 0000000..4f302d7
--- /dev/null
@@ -0,0 +1,32 @@
+# -*- makefile -*-
+
+default_CONFIG = CONFIG_APP_USBCAN=n
+
+ifeq ($(CONFIG_APP_USBCAN),y)
+
+#ULAN_ID=usbtest
+
+#default_CONFIG += CONFIG_ULOI_LT=x
+#default_CONFIG += CONFIG_ULAN_DY=x
+default_CONFIG += MACH=$(MACH)
+#default_CONFIG += ULAN_ID=$(ULAN_ID)
+default_CONFIG += CONFIG_MISC_VECT=x
+
+LOCAL_CONFIG_H = local_config.h
+
+INCLUDES += -I.
+
+#include_HEADERS  = ul_idstr.h
+
+bin_PROGRAMS = usbcan
+usbcan_SOURCES = main.c usb_srq.c can.c can_queue.c sja1000p.c can_quesysless.c devcommon.c setup.c ul_usb1.c finish.c usb_vend.c
+
+#usbtest_SOURCES +=  ul_idstr.c
+#lib_LOADLIBES =  bspbase ul_drv lpciap keyval lpciap_kvpb mach_hal uldy
+lib_LOADLIBES =  bspbase usbbase lpcusb mach_hal
+usbcan_MOREOBJS = $(USER_LIB_DIR)/system_stub.o $(USER_LIB_DIR)/ivt.o
+nobase_include_HEADERS = usb/usb_defs.h
+
+link_VARIANTS = boot
+
+endif #CONFIG_ULBOOT
diff --git a/embedded/app/usbcan/can.c b/embedded/app/usbcan/can.c
new file mode 100644 (file)
index 0000000..25d7f34
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+can.c
+
+Routines for sending and receiving messages for configuration and/or
+communication over CAN network using a SJA1000 transceiver.
+For use in UL_USB1 module, it runs in Intel mode.
+See documentation for details.
+
+*/
+
+
+#include "can/can.h"
+
+/// Baud rates
+#if SJA1000_CLK==(24000000)
+       /*      Bus speed, Precaler, SJW, TSEG1, TSEG2
+        *      For SJW setting we assume 1% xtal accuracy
+        */
+       const long sja1000_freqs[3][5]=
+       {{1000, 0x00,   0xC0,   0x08,   0x10}
+       ,{250,  0x02,   0xC0,   0x0A,   0x30}
+       ,{100,  0x07,   0xC0,   0x09,   0x30}};
+       const int sja1000_freq_cnt=3;
+#endif
+
+struct can_baudparams_t canbaud;
+
+void can_comm_init()
+{
+       // Due to change in design there is CS_PIN connected with ALE_PIN and ALE_PIN connection to LPC is interrupted
+       // We don't use ALE_PIN
+       //IO0DIR|=P0_SJA1000_ALE_PIN|P0_SJA1000_CS_PIN|P0_SJA1000_RD_PIN|P0_SJA1000_WR_PIN;
+       IO0DIR|=P0_SJA1000_CS_PIN|P0_SJA1000_RD_PIN|P0_SJA1000_WR_PIN;
+       IO0DIR&=~(P0_SJA1000_INT_PIN);
+
+       SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+       CLR_OUT_PIN(IO1,P1_SJA1000_RST_PIN);
+       SJA1000_INIT_DELAY();
+       SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+       // Due to change in design there is CS_PIN connected with ALE_PIN and ALE_PIN connection to LPC is interrupted
+       //      CLR_OUT_PIN(IO0,P0_SJA1000_ALE_PIN);
+       SET_OUT_PIN(IO1,P1_SJA1000_RST_PIN);
+       SJA1000_INIT_DELAY();
+}
+
+int can_write(uint8_t address,uint8_t* data)
+{
+       IO1DIR|=0x00FF0000; // Port as output to send data
+       IO1CLR=0x00FF0000; // Clear all data on port
+       // Init
+       SET_OUT_PIN(IO0,P0_SJA1000_RD_PIN);     // Stays high on write
+       SET_OUT_PIN(IO0,P0_SJA1000_WR_PIN); // Stays high on address write
+       SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN); // Sets output buffers to third state
+       SJA1000_DELAY();
+       //SET_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); // Start command
+
+       // Set memory address
+       IO1SET=__val2mfld(0x00FF0000,address); // Shift data to SJA pins and output them
+       SJA1000_DELAY();
+       //CLR_OUT_PIN(IO0,P0_SJA1000_ALE_PIN); // Makes address active
+       CLR_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+       SJA1000_DELAY();
+
+       // Setting data
+       CLR_OUT_PIN(IO0,P0_SJA1000_WR_PIN);
+
+       IO1CLR=0x00FF0000;
+       IO1SET=__val2mfld(0x00FF0000,*data);
+       SJA1000_DELAY();
+       SET_OUT_PIN(IO0,P0_SJA1000_WR_PIN); // Data should be accepted by now
+       SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+       SJA1000_DELAY();
+       return 0;
+}
+
+int can_read(const uint8_t address,uint8_t* data)
+{
+       IO1DIR|=0x00FF0000; // Port as output to set address
+       IO1CLR=0x00FF0000; // Clear all data
+       // Init
+       SET_OUT_PIN(IO0,P0_SJA1000_WR_PIN); // Stays high on read
+       SET_OUT_PIN(IO0,P0_SJA1000_RD_PIN); // Stays high while entering address
+       SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+       SJA1000_DELAY();
+       //SET_OUT_PIN(IO0,P0_SJA1000_ALE_PIN);
+
+       // Request memory address
+       IO1SET=__val2mfld(0x00FF0000,address);
+       SJA1000_DELAY();
+       //CLR_OUT_PIN(IO0,P0_SJA1000_ALE_PIN);
+       CLR_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+
+       // Get data
+
+       IO1DIR&=~0x00FF0000; // Sets port as input
+       CLR_OUT_PIN(IO0,P0_SJA1000_RD_PIN);
+       SJA1000_DELAY();
+       *data=__mfld2val(0x00FF0000,IO1PIN);
+       SET_OUT_PIN(IO0,P0_SJA1000_RD_PIN);
+       SET_OUT_PIN(IO0,P0_SJA1000_CS_PIN);
+       SJA1000_DELAY();
+       return 0;
+}
+
+int can_init(){
+       uint8_t data=0,count=0;
+       do {
+               can_comm_init();
+               can_read(SJAMOD,&data);
+               if (count++ > 50)
+                       return -1;
+       } while (!(data&sjaMOD_RM));
+
+       data=sjaCDR_CLKOUT_DIV1|sjaCDR_CLK_OFF|sjaCDR_CBP|sjaCDR_PELICAN;
+       can_write((uint8_t)SJACDR,(uint8_t*)&data);
+
+       // Single acceptance filter, reset mode
+       data=sjaMOD_AFM|sjaMOD_RM;
+       can_write((uint8_t)SJAMOD,(uint8_t*)&data);
+
+       // Enabling all interrupt sources
+       data=sjaENABLE_INTERRUPTS;
+       can_write((uint8_t)SJAIER,(uint8_t*)&data);
+
+       // Accept all messages
+       data=0xFF;
+       can_write((uint8_t)SJAAMR0,(uint8_t*)&data);
+       can_write((uint8_t)SJAAMR0+1,(uint8_t*)&data);
+       can_write((uint8_t)SJAAMR0+2,(uint8_t*)&data);
+       can_write((uint8_t)SJAAMR0+3,(uint8_t*)&data);
+
+       data=sjaCMR_CDO;
+       can_write((uint8_t)SJACMR,(uint8_t*)&data);
+
+       return 0;
+}
diff --git a/embedded/app/usbcan/can/can.h b/embedded/app/usbcan/can/can.h
new file mode 100644 (file)
index 0000000..4dacadf
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef        SJA1000_CAN_H
+#define SJA1000_CAN_H
+
+#include <stdio.h>
+#include <string.h>
+#include <cpu_def.h>
+#include <system_def.h>
+#include <lt_timer.h>
+#include <local_config.h>
+#include <usb/usbdebug.h>
+#include <usb/usb.h>
+#include <usb/lpc.h>
+#include <usb/usb_srq.h>
+#include <mem_loc.h>
+#include <hal_machperiph.h>
+
+
+#include "main.h"
+#include "sja1000p.h"
+/* can.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+ /*
+               Delay for synchronization with peripheral (SJA1000)
+ */
+       #define SJA1000_CLK (24000000)  /* XTAL frequency */
+       #define SJA1000_PRESC (2)       /* embedded prescaler */
+       #define SJA1000_CCLK (SJA1000_CLK/SJA1000_PRESC)        /* SJA core frequency */
+       #define SJA1000_SCLK (PCLK/SJA1000_CCLK)        /* Clock count to synchronize with LPC */
+
+       #define SJA1000_DELAY(void)     \
+                       ({ \
+                               volatile int delay; \
+                               for (delay=0;delay<SJA1000_SCLK;delay++) \
+                                       IO0SET=0; \
+                       })
+       #define SJA1000_INIT_DELAY(void)        \
+                       ({ \
+                               volatile int delay; \
+                               for (delay=0;delay<20*SJA1000_SCLK;delay++) \
+                                       IO0SET=0; \
+                       })
+
+/**
+ * struct can_baudparams_t - datatype for calling CONF_BAUDPARAMS IOCTL
+ * @flags: reserved for additional flags for chip configuration, should be written -1 or 0
+ * @baudrate: baud rate in Hz
+ * @sjw: synchronization jump width (0-3) prescaled clock cycles
+ * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio
+ *
+ * The structure is used to configure new set of parameters into CAN controller chip.
+ * If default value of some field should be preserved, fill field by value -1.
+ */
+struct can_baudparams_t {
+       long flags;
+       long baudrate;
+       long sjw;
+       long sample_pt;
+};
+
+extern int can_init();
+extern int can_read(uint8_t address,uint8_t *data);
+extern int can_write(uint8_t address,uint8_t *data);
+
+#endif /* SJA1000_CAN_H */
diff --git a/embedded/app/usbcan/can/can_queue.h b/embedded/app/usbcan/can/can_queue.h
new file mode 100644 (file)
index 0000000..42eeef4
--- /dev/null
@@ -0,0 +1,809 @@
+/* can_queue.h - CAN queues and message passing infrastructure 
+ * Linux CAN-bus device driver.
+ * Written by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef _CAN_QUEUE_H
+#define _CAN_QUEUE_H
+
+#include "./canmsg.h"
+#include "./constants.h"
+#include "./can_sysdep.h"
+
+/**
+ * struct canque_slot_t - one CAN message slot in the CAN FIFO queue 
+ * @next: pointer to the next/younger slot
+ * @slot_flags: space for flags and optional command describing action
+ *     associated with slot data
+ * @msg: space for one CAN message
+ *
+ * This structure is used to store CAN messages in the CAN FIFO queue.
+ */
+ struct canque_slot_t {
+       struct canque_slot_t *next;
+       unsigned long slot_flags;
+       struct canmsg_t msg;
+};
+
+#define CAN_SLOTF_CMD  0x00ff  /*  */
+
+/**
+ * struct canque_fifo_t - CAN FIFO queue representation
+ * @fifo_flags: this field holds global flags describing state of the FIFO.
+ *     %CAN_FIFOF_ERROR is set when some error condition occurs.
+ *     %CAN_FIFOF_ERR2BLOCK defines, that error should lead to the FIFO block state.
+ *     %CAN_FIFOF_BLOCK state blocks insertion of the next messages. 
+ *     %CAN_FIFOF_OVERRUN attempt to acquire new slot, when FIFO is full. 
+ *     %CAN_FIFOF_FULL indicates FIFO full state. 
+ *     %CAN_FIFOF_EMPTY indicates no allocated slot in the FIFO.
+ *     %CAN_FIFOF_DEAD condition indication. Used when FIFO is beeing destroyed.
+ * @error_code: futher description of error condition
+ * @head: pointer to the FIFO head, oldest slot
+ * @tail: pointer to the location, where pointer to newly inserted slot
+ *     should be added
+ * @flist: pointer to list of the free slots associated with queue
+ * @entry: pointer to the memory allocated for the list slots.
+ * @fifo_lock: the lock to ensure atomicity of slot manipulation operations.
+ * @slotsnr:  number of allocated slots
+ *
+ * This structure represents CAN FIFO queue. It is implemented as 
+ * a single linked list of slots prepared for processing. The empty slots
+ * are stored in single linked list (@flist).
+ */
+struct canque_fifo_t {
+       unsigned long fifo_flags;
+       unsigned long error_code;
+       struct canque_slot_t *head;     /* points to the oldest entry */
+       struct canque_slot_t **tail;    /* points to NULL pointer for chaining */
+       struct canque_slot_t *flist;    /* points the first entry in the free list */
+       struct canque_slot_t *entry;    /* points to first allocated entry */
+       can_spinlock_t fifo_lock;       /* can_spin_lock_irqsave / can_spin_unlock_irqrestore */
+       int    slotsnr;
+};
+
+#define CAN_FIFOF_DESTROY_b    15
+#define CAN_FIFOF_ERROR_b      14
+#define CAN_FIFOF_ERR2BLOCK_b  13
+#define CAN_FIFOF_BLOCK_b      12
+#define CAN_FIFOF_OVERRUN_b    11
+#define CAN_FIFOF_FULL_b       10
+#define CAN_FIFOF_EMPTY_b      9
+#define CAN_FIFOF_DEAD_b       8
+#define CAN_FIFOF_INACTIVE_b   7
+#define CAN_FIFOF_FREEONEMPTY_b        6
+#define CAN_FIFOF_READY_b      5
+#define CAN_FIFOF_NOTIFYPEND_b 4
+#define CAN_FIFOF_RTL_MEM_b    3
+
+#define CAN_FIFOF_DESTROY      (1<<CAN_FIFOF_DESTROY_b)
+#define CAN_FIFOF_ERROR                (1<<CAN_FIFOF_ERROR_b)
+#define CAN_FIFOF_ERR2BLOCK    (1<<CAN_FIFOF_ERR2BLOCK_b)
+#define CAN_FIFOF_BLOCK                (1<<CAN_FIFOF_BLOCK_b)
+#define CAN_FIFOF_OVERRUN      (1<<CAN_FIFOF_OVERRUN_b)
+#define CAN_FIFOF_FULL         (1<<CAN_FIFOF_FULL_b)
+#define CAN_FIFOF_EMPTY                (1<<CAN_FIFOF_EMPTY_b)
+#define CAN_FIFOF_DEAD         (1<<CAN_FIFOF_DEAD_b)
+#define CAN_FIFOF_INACTIVE     (1<<CAN_FIFOF_INACTIVE_b)
+#define CAN_FIFOF_FREEONEMPTY  (1<<CAN_FIFOF_FREEONEMPTY_b)
+#define CAN_FIFOF_READY                (1<<CAN_FIFOF_READY_b)
+#define CAN_FIFOF_NOTIFYPEND    (1<<CAN_FIFOF_NOTIFYPEND_b)
+#define CAN_FIFOF_RTL_MEM       (1<<CAN_FIFOF_RTL_MEM_b)
+
+#define canque_fifo_test_fl(fifo,fifo_fl) \
+  test_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
+#define canque_fifo_set_fl(fifo,fifo_fl) \
+  set_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
+#define canque_fifo_clear_fl(fifo,fifo_fl) \
+  clear_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
+#define canque_fifo_test_and_set_fl(fifo,fifo_fl) \
+  test_and_set_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
+#define canque_fifo_test_and_clear_fl(fifo,fifo_fl) \
+  test_and_clear_bit(CAN_FIFOF_##fifo_fl##_b,&(fifo)->fifo_flags)
+
+
+/**
+ * canque_fifo_get_inslot - allocate slot for the input of one CAN message 
+ * @fifo: pointer to the FIFO structure
+ * @slotp: pointer to location to store pointer to the allocated slot.
+ * @cmd: optional command associated with allocated slot.
+ *
+ * Return Value: The function returns negative value if there is no
+ *     free slot in the FIFO queue.
+ */
+static inline
+int canque_fifo_get_inslot(struct canque_fifo_t *fifo, struct canque_slot_t **slotp, int cmd)
+{
+       can_spin_irqflags_t flags;
+       struct canque_slot_t *slot;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       /* get the first free slot slot from flist */
+       if(!(slot=fifo->flist)) {
+               canque_fifo_set_fl(fifo,OVERRUN);
+               canque_fifo_set_fl(fifo,FULL);
+               can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+               *slotp=NULL;
+               return -1;
+       }
+       /* adjust free slot list */
+       if(!(fifo->flist=slot->next))
+               canque_fifo_set_fl(fifo,FULL);
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+       *slotp=slot;
+       slot->slot_flags=cmd&CAN_SLOTF_CMD;
+       return 1;
+}
+
+/**
+ * canque_fifo_put_inslot - releases slot to further processing
+ * @fifo: pointer to the FIFO structure
+ * @slot: pointer to the slot previously acquired by canque_fifo_get_inslot().
+ *
+ * Return Value: The nonzero return value indicates, that the queue was empty
+ *     before call to the function. The caller should wake-up output side of the queue.
+ */
+static inline
+int canque_fifo_put_inslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot)
+{
+       int ret;
+       can_spin_irqflags_t flags;
+       slot->next=NULL;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       if(*fifo->tail) can_printk(KERN_CRIT "canque_fifo_put_inslot: fifo->tail != NULL\n");
+       *fifo->tail=slot;
+       fifo->tail=&slot->next;
+       ret=0;
+       if(canque_fifo_test_and_clear_fl(fifo,EMPTY))
+         ret=CAN_FIFOF_EMPTY;  /* Fifo has been empty before put */
+       if(canque_fifo_test_and_clear_fl(fifo,INACTIVE))
+         ret=CAN_FIFOF_INACTIVE; /* Fifo has been empty before put */
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+       return ret;
+}
+
+/**
+ * canque_fifo_abort_inslot - release and abort slot
+ * @fifo: pointer to the FIFO structure
+ * @slot: pointer to the slot previously acquired by canque_fifo_get_inslot().
+ *
+ * Return Value: The nonzero value indicates, that fifo was full
+ */
+static inline
+int canque_fifo_abort_inslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot)
+{
+       int ret=0;
+       can_spin_irqflags_t flags;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       slot->next=fifo->flist;
+       fifo->flist=slot;
+       if(canque_fifo_test_and_clear_fl(fifo,FULL))
+               ret=CAN_FIFOF_FULL;
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+       return ret;
+}
+
+/**
+ * canque_fifo_test_outslot - test and get ready slot from the FIFO
+ * @fifo: pointer to the FIFO structure
+ * @slotp: pointer to location to store pointer to the oldest slot from the FIFO.
+ *
+ * Return Value: The negative value indicates, that queue is empty.
+ *     The positive or zero value represents command stored into slot by
+ *     the call to the function canque_fifo_get_inslot().
+ *     The successfully acquired FIFO output slot has to be released by
+ *     the call canque_fifo_free_outslot() or canque_fifo_again_outslot().
+ */
+static inline
+int canque_fifo_test_outslot(struct canque_fifo_t *fifo, struct canque_slot_t **slotp)
+{
+       can_spin_irqflags_t flags;
+       int cmd;
+       struct canque_slot_t *slot;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       if(!(slot=fifo->head)){;
+               canque_fifo_set_fl(fifo,EMPTY);
+               can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+               *slotp=NULL;
+               return -1;
+       }
+       if(!(fifo->head=slot->next))
+               fifo->tail=&fifo->head;
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+
+       *slotp=slot;
+       cmd=slot->slot_flags;
+       return cmd&CAN_SLOTF_CMD;
+}
+
+
+/**
+ * canque_fifo_free_outslot - free processed FIFO slot
+ * @fifo: pointer to the FIFO structure
+ * @slot: pointer to the slot previously acquired by canque_fifo_test_outslot().
+ *
+ * Return Value: The returned value informs about FIFO state change.
+ *     The mask %CAN_FIFOF_FULL indicates, that the FIFO was full before
+ *     the function call. The mask %CAN_FIFOF_EMPTY informs, that last ready slot
+ *     has been processed.
+ */
+static inline
+int canque_fifo_free_outslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot)
+{
+       int ret=0;
+       can_spin_irqflags_t flags;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       slot->next=fifo->flist;
+       fifo->flist=slot;
+       if(canque_fifo_test_and_clear_fl(fifo,FULL))
+               ret=CAN_FIFOF_FULL;
+       if(!(fifo->head)){
+               canque_fifo_set_fl(fifo,EMPTY);
+               ret|=CAN_FIFOF_EMPTY;
+       }
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+       return ret;
+}
+
+/**
+ * canque_fifo_again_outslot - interrupt and postpone processing of the slot
+ * @fifo: pointer to the FIFO structure
+ * @slot: pointer to the slot previously acquired by canque_fifo_test_outslot().
+ *
+ * Return Value: The function cannot fail..
+ */
+static inline
+int canque_fifo_again_outslot(struct canque_fifo_t *fifo, struct canque_slot_t *slot)
+{
+       can_spin_irqflags_t flags;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       if(!(slot->next=fifo->head))
+               fifo->tail=&slot->next;
+       fifo->head=slot;
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+       return 1;
+}
+
+int canque_fifo_flush_slots(struct canque_fifo_t *fifo);
+
+int canque_fifo_init_slots(struct canque_fifo_t *fifo);
+
+#define CANQUEUE_PRIO_NR  3
+
+/* Forward declarations for external types */
+struct msgobj_t;
+struct canchip_t;
+
+/**
+ * struct canque_edge_t - CAN message delivery subsystem graph edge
+ * @fifo: place where primitive @struct canque_fifo_t FIFO is located.
+ * @filtid: the possible CAN message identifiers filter.
+ * @filtmask: the filter mask, the comparison considers only
+ *     @filtid bits corresponding to set bits in the @filtmask field.
+ * @inpeers: the lists of all peers FIFOs connected by their
+ *     input side (@inends) to the same terminal (@struct canque_ends_t).
+ * @outpeers: the lists of all peers FIFOs connected by their
+ *     output side (@outends) to the same terminal (@struct canque_ends_t).
+ * @activepeers: the lists of peers FIFOs connected by their
+ *     output side (@outends) to the same terminal (@struct canque_ends_t)
+ *     with same priority and active state.
+ * @inends: the pointer to the FIFO input side terminal (@struct canque_ends_t).
+ * @outends: the pointer to the FIFO output side terminal (@struct canque_ends_t).
+ * @edge_used: the atomic usage counter, mainly used for safe destruction of the edge.
+ * @edge_prio: the assigned queue priority from the range 0 to %CANQUEUE_PRIO_NR-1
+ * @edge_num: edge sequential number intended for debugging purposes only
+ * @pending_peers: edges with pending delayed events (RTL->Linux calls)
+ * @pending_inops: bitmask of pending operations
+ * @pending_outops: bitmask of pending operations
+ *
+ * This structure represents one direction connection from messages source 
+ * (@inends) to message consumer (@outends) fifo ends hub. The edge contains
+ * &struct canque_fifo_t for message fifo implementation.
+ */
+struct canque_edge_t {
+       struct canque_fifo_t fifo;
+       unsigned long filtid;
+       unsigned long filtmask;
+       struct list_head inpeers;
+       struct list_head outpeers;
+       struct list_head activepeers;
+       struct canque_ends_t *inends;
+       struct canque_ends_t *outends;
+       atomic_t edge_used;
+       int edge_prio;
+       int edge_num;
+    #ifdef CAN_WITH_RTL
+       struct list_head pending_peers;
+       unsigned long pending_inops;
+       unsigned long pending_outops;
+    #endif /*CAN_WITH_RTL*/
+};
+
+/**
+ * struct canque_ends_t - CAN message delivery subsystem graph vertex (FIFO ends)
+ * @ends_flags: this field holds flags describing state of the ENDS structure.
+ * @active: the array of the lists of active edges directed to the ends structure
+ *     with ready messages. The array is indexed by the edges priorities. 
+ * @idle: the list of the edges directed to the ends structure with empty FIFOs.
+ * @inlist: the list of outgoing edges input sides.
+ * @outlist: the list of all incoming edges output sides. Each of there edges
+ *     is listed on one of @active or @idle lists.
+ * @ends_lock: the lock synchronizing operations between threads accessing
+ *     same ends structure.
+ * @notify: pointer to notify procedure. The next state changes are notified.
+ *     %CANQUEUE_NOTIFY_EMPTY (out->in call) - all slots are processed by FIFO out side. 
+ *     %CANQUEUE_NOTIFY_SPACE (out->in call) - full state negated => there is space for new message.
+ *     %CANQUEUE_NOTIFY_PROC  (in->out call) - empty state negated => out side is requested to process slots.
+ *     %CANQUEUE_NOTIFY_NOUSR (both) - notify, that the last user has released the edge usage
+ *             called with some lock to prevent edge disappear.
+ *     %CANQUEUE_NOTIFY_DEAD  (both) - edge is in progress of deletion.
+ *     %CANQUEUE_NOTIFY_ATACH (both) - new edge has been attached to end.
+ *     %CANQUEUE_NOTIFY_FILTCH (out->in call) - edge filter rules changed
+ *     %CANQUEUE_NOTIFY_ERROR  (out->in call) - error in messages processing.
+ * @context: space to store ends user specific information
+ * @endinfo: space to store some other ends usage specific informations
+ *     mainly for waking-up by the notify calls.
+ * @dead_peers: used to chain ends wanting for postponed destruction
+ *
+ * Structure represents place to connect edges to for CAN communication entity.
+ * The zero, one or more incoming and outgoing edges can be connected to
+ * this structure.
+ */
+struct canque_ends_t {
+       unsigned long ends_flags;
+       struct list_head active[CANQUEUE_PRIO_NR];
+       struct list_head idle;
+       struct list_head inlist;
+       struct list_head outlist;
+       can_spinlock_t ends_lock;       /* can_spin_lock_irqsave / can_spin_unlock_irqrestore */
+       void (*notify)(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what);
+       void *context;
+       union {
+               struct {
+                       wait_queue_head_t readq;
+                       wait_queue_head_t writeq;
+                       wait_queue_head_t emptyq;
+                   #ifdef CAN_ENABLE_KERN_FASYNC
+                       struct fasync_struct *fasync;
+                   #endif /*CAN_ENABLE_KERN_FASYNC*/
+               } fileinfo;
+           #ifdef CAN_WITH_RTL
+               struct {
+                       rtl_spinlock_t rtl_lock;
+                       rtl_wait_t rtl_readq;
+                       atomic_t   rtl_readq_age;
+                       rtl_wait_t rtl_writeq;
+                       atomic_t   rtl_writeq_age;
+                       rtl_wait_t rtl_emptyq;
+                       atomic_t   rtl_emptyq_age;
+                       unsigned long pend_flags;
+               } rtlinfo;
+           #endif /*CAN_WITH_RTL*/
+               struct {
+                       struct msgobj_t *msgobj;
+                       struct canchip_t *chip;
+                   #ifndef CAN_WITH_RTL
+                       wait_queue_head_t daemonq;
+                   #else /*CAN_WITH_RTL*/
+                       pthread_t worker_thread;
+                   #endif /*CAN_WITH_RTL*/
+               } chipinfo;
+       } endinfo;
+       struct list_head dead_peers;
+};
+
+#define CANQUEUE_NOTIFY_EMPTY  1 /* out -> in - all slots are processed by FIFO out side */
+#define CANQUEUE_NOTIFY_SPACE  2 /* out -> in - full state negated => there is space for new message */
+#define CANQUEUE_NOTIFY_PROC   3 /* in -> out - empty state negated => out side is requested to process slots */
+#define CANQUEUE_NOTIFY_NOUSR  4 /* called with some lock to prevent edge disappear */
+#define CANQUEUE_NOTIFY_DEAD   5 /*  */
+#define CANQUEUE_NOTIFY_DEAD_WANTED 6 /*  */
+#define CANQUEUE_NOTIFY_ATTACH 7 /*  */
+#define CANQUEUE_NOTIFY_FILTCH 8 /* filter changed */
+#define CANQUEUE_NOTIFY_ERROR      0x10000 /* error notifiers */
+#define CANQUEUE_NOTIFY_ERRTX_PREP 0x11001 /* tx preparation error */
+#define CANQUEUE_NOTIFY_ERRTX_SEND 0x11002 /* tx send error */
+#define CANQUEUE_NOTIFY_ERRTX_BUS  0x11003 /* tx bus error */
+
+#define CAN_ENDSF_DEAD   (1<<0)
+#define CAN_ENDSF_MEM_RTL (1<<1)
+
+/**
+ * canque_notify_inends - request to send notification to the input ends
+ * @qedge: pointer to the edge structure
+ * @what: notification type
+ */
+static inline
+void canque_notify_inends(struct canque_edge_t *qedge, int what)
+{
+       if(qedge->inends)
+               if(qedge->inends->notify)
+                       qedge->inends->notify(qedge->inends,qedge,what);
+}
+
+/**
+ * canque_notify_outends - request to send notification to the output ends
+ * @qedge: pointer to the edge structure
+ * @what: notification type
+ */
+static inline
+void canque_notify_outends(struct canque_edge_t *qedge, int what)
+{
+       if(qedge->outends)
+               if(qedge->outends->notify)
+                       qedge->outends->notify(qedge->outends,qedge,what);
+}
+
+/**
+ * canque_notify_bothends - request to send notification to the both ends
+ * @qedge: pointer to the edge structure
+ * @what: notification type
+ */
+static inline
+void canque_notify_bothends(struct canque_edge_t *qedge, int what)
+{
+       canque_notify_inends(qedge, what);
+       canque_notify_outends(qedge, what);
+}
+
+/**
+ * canque_activate_edge - mark output end of the edge as active
+ * @qedge: pointer to the edge structure
+ * @inends: input side of the edge
+ *
+ * Function call moves output side of the edge from idle onto active edges
+ * list. This function has to be called with edge reference count held.
+ * that is same as for most of other edge functions.
+ */
+static inline
+void canque_activate_edge(struct canque_ends_t *inends, struct canque_edge_t *qedge)
+{
+       can_spin_irqflags_t flags;
+       struct canque_ends_t *outends;
+       if(qedge->edge_prio>=CANQUEUE_PRIO_NR)
+               qedge->edge_prio=CANQUEUE_PRIO_NR-1;
+       if((outends=qedge->outends)){
+               can_spin_lock_irqsave(&outends->ends_lock, flags);
+               can_spin_lock(&qedge->fifo.fifo_lock);
+               if(!canque_fifo_test_fl(&qedge->fifo,EMPTY)){
+                       list_del(&qedge->activepeers);
+                       list_add_tail(&qedge->activepeers,&outends->active[qedge->edge_prio]);
+               }
+               can_spin_unlock(&qedge->fifo.fifo_lock);
+               can_spin_unlock_irqrestore(&outends->ends_lock, flags);
+       }
+}
+
+/**
+ * canque_filtid2internal - converts message ID and filter flags into internal format
+ * @id: CAN message 11 or 29 bit identifier
+ * @filtflags: CAN message flags
+ *
+ * This function maps message ID and %MSG_RTR, %MSG_EXT and %MSG_LOCAL into one 32 bit number
+ */
+static inline
+unsigned int canque_filtid2internal(unsigned long id, int filtflags)
+{
+       filtflags &= MSG_RTR|MSG_EXT|MSG_LOCAL;
+       filtflags += filtflags&MSG_RTR;
+       return (id&MSG_ID_MASK) | (filtflags<<28);
+}
+
+int canque_get_inslot(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd);
+       
+int canque_get_inslot4id(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio);
+       
+int canque_put_inslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot);
+
+int canque_abort_inslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot);
+
+int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg);
+
+int canque_test_outslot(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp);
+
+int canque_free_outslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot);
+
+int canque_again_outslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot);
+
+int canque_set_filt(struct canque_edge_t *qedge,
+       unsigned long filtid, unsigned long filtmask, int flags);
+       
+int canque_flush(struct canque_edge_t *qedge);
+
+int canqueue_disconnect_edge(struct canque_edge_t *qedge);
+
+int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends);
+
+int canqueue_ends_init_gen(struct canque_ends_t *qends);
+
+void canqueue_block_inlist(struct canque_ends_t *qends);
+
+void canqueue_block_outlist(struct canque_ends_t *qends);
+
+int canqueue_ends_kill_inlist(struct canque_ends_t *qends, int send_rest);
+
+int canqueue_ends_kill_outlist(struct canque_ends_t *qends);
+
+int canqueue_ends_filt_conjuction(struct canque_ends_t *qends, struct canfilt_t *filt);
+
+int canqueue_ends_flush_inlist(struct canque_ends_t *qends);
+
+int canqueue_ends_flush_outlist(struct canque_ends_t *qends);
+
+/* edge reference and traversal functions */
+
+void canque_edge_do_dead(struct canque_edge_t *edge);
+
+/**
+ * canque_edge_incref - increments edge reference count
+ * @edge: pointer to the edge structure
+ */
+static inline
+void canque_edge_incref(struct canque_edge_t *edge)
+{
+       atomic_inc(&edge->edge_used);
+}
+
+static inline
+can_spin_irqflags_t canque_edge_lock_both_ends(struct canque_ends_t *inends, struct canque_ends_t *outends)
+{
+       can_spin_irqflags_t  flags;
+       if(inends<outends) {
+               can_spin_lock_irqsave(&inends->ends_lock, flags);
+               can_spin_lock(&outends->ends_lock);
+       }else{
+               can_spin_lock_irqsave(&outends->ends_lock, flags);
+               if(outends!=inends) can_spin_lock(&inends->ends_lock);
+       }
+       return flags;   
+}
+
+static inline
+void canque_edge_unlock_both_ends(struct canque_ends_t *inends, struct canque_ends_t *outends, can_spin_irqflags_t flags)
+{
+       if(outends!=inends) can_spin_unlock(&outends->ends_lock);
+       can_spin_unlock_irqrestore(&inends->ends_lock, flags);
+}
+
+/* Non-inlined version of edge reference decrement */
+void __canque_edge_decref(struct canque_edge_t *edge);
+
+static inline
+void __canque_edge_decref_body(struct canque_edge_t *edge)
+{
+       can_spin_irqflags_t flags;
+       int dead_fl=0;
+       struct canque_ends_t *inends=edge->inends;
+       struct canque_ends_t *outends=edge->outends;
+       
+       flags=canque_edge_lock_both_ends(inends, outends);
+       if(atomic_dec_and_test(&edge->edge_used)) {
+               dead_fl=!canque_fifo_test_and_set_fl(&edge->fifo,DEAD);
+               /* Because of former evolution of edge references 
+                  management notify of CANQUEUE_NOTIFY_NOUSR could
+                  be moved to canque_edge_do_dead :-) */
+       }
+       canque_edge_unlock_both_ends(inends, outends, flags);
+       if(dead_fl) canque_edge_do_dead(edge);
+}
+
+#ifndef CAN_HAVE_ARCH_CMPXCHG
+/**
+ * canque_edge_decref - decrements edge reference count
+ * @edge: pointer to the edge structure
+ *
+ * This function has to be called without lock held for both ends of edge.
+ * If reference count drops to 0, function canque_edge_do_dead()
+ * is called.
+ */
+static inline
+void canque_edge_decref(struct canque_edge_t *edge)
+{
+       __canque_edge_decref_body(edge);
+}
+#else
+static inline
+void canque_edge_decref(struct canque_edge_t *edge)
+{
+       int x, y;
+       
+        x = atomic_read(&edge->edge_used);
+        do{
+               if(x<=1)
+                       return __canque_edge_decref(edge);
+               y=x;
+               /* This code strongly depends on the definition of atomic_t !!!! */
+               /* x=cmpxchg(&edge->edge_used, x, x-1); */
+               /* Next alternative could be more portable */
+               x=__cmpxchg(&edge->edge_used, x, x-1, sizeof(atomic_t));
+               /* If even this does not help, comment out CAN_HAVE_ARCH_CMPXCHG in can_sysdep.h */
+       } while(x!=y);
+}
+#endif
+
+static inline
+struct canque_edge_t *canque_first_inedge(struct canque_ends_t *qends)
+{
+       can_spin_irqflags_t flags;
+       struct list_head *entry;
+       struct canque_edge_t *edge;
+       
+       can_spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=qends->inlist.next;
+    skip_dead:
+       if(entry != &qends->inlist) {
+               edge=list_entry(entry,struct canque_edge_t,inpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(edge);
+       } else {
+               edge=NULL;
+       }
+       can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+       return edge;
+}
+
+
+static inline
+struct canque_edge_t *canque_next_inedge(struct canque_ends_t *qends, struct canque_edge_t *edge)
+{
+       can_spin_irqflags_t flags;
+       struct list_head *entry;
+       struct canque_edge_t *next;
+       
+       can_spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=edge->inpeers.next;
+    skip_dead:
+       if(entry != &qends->inlist) {
+               next=list_entry(entry,struct canque_edge_t,inpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(next);
+       } else {
+               next=NULL;
+       }
+       can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(edge);
+       return next;
+}
+
+#define canque_for_each_inedge(qends, edge) \
+           for(edge=canque_first_inedge(qends);edge;edge=canque_next_inedge(qends, edge))
+
+static inline
+struct canque_edge_t *canque_first_outedge(struct canque_ends_t *qends)
+{
+       can_spin_irqflags_t flags;
+       struct list_head *entry;
+       struct canque_edge_t *edge;
+       
+       can_spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=qends->outlist.next;
+    skip_dead:
+       if(entry != &qends->outlist) {
+               edge=list_entry(entry,struct canque_edge_t,outpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(edge);
+       } else {
+               edge=NULL;
+       }
+       can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+       return edge;
+}
+
+
+static inline
+struct canque_edge_t *canque_next_outedge(struct canque_ends_t *qends, struct canque_edge_t *edge)
+{
+       can_spin_irqflags_t flags;
+       struct list_head *entry;
+       struct canque_edge_t *next;
+       
+       can_spin_lock_irqsave(&qends->ends_lock, flags);
+       entry=edge->outpeers.next;
+    skip_dead:
+       if(entry != &qends->outlist) {
+               next=list_entry(entry,struct canque_edge_t,outpeers);
+               if(canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                       entry=entry->next;
+                       goto skip_dead;
+               }
+               canque_edge_incref(next);
+       } else {
+               next=NULL;
+       }
+       can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(edge);
+       return next;
+}
+
+#define canque_for_each_outedge(qends, edge) \
+           for(edge=canque_first_outedge(qends);edge;edge=canque_next_outedge(qends, edge))
+
+/* Linux kernel specific functions */
+
+int canque_fifo_init_kern(struct canque_fifo_t *fifo, int slotsnr);
+
+int canque_fifo_done_kern(struct canque_fifo_t *fifo);
+
+struct canque_edge_t *canque_new_edge_kern(int slotsnr);
+
+int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio);
+
+int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp);
+
+int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge);
+
+int canqueue_ends_init_kern(struct canque_ends_t *qends);
+
+int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync);
+
+void canqueue_ends_dispose_postpone(struct canque_ends_t *qends);
+
+void canqueue_kern_initialize(void);
+
+#ifdef CAN_WITH_RTL
+
+extern struct tasklet_struct canque_dead_tl;   /*publication required only for RTL*/
+
+/* RT-Linux specific functions and variables */
+
+extern int canqueue_rtl_irq;
+
+extern unsigned long canqueue_rtl2lin_pend;
+
+#define CAN_RTL2LIN_PEND_DEAD_b 0
+
+void canqueue_rtl_initialize(void);
+void canqueue_rtl_done(void);
+
+int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
+                        struct canque_edge_t *qedge, int what);
+
+struct canque_edge_t *canque_new_edge_rtl(int slotsnr);
+
+void canque_dispose_edge_rtl(struct canque_edge_t *qedge);
+
+int canque_get_inslot4id_wait_rtl(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio);
+
+int canque_get_outslot_wait_rtl(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp);
+
+int canque_sync_wait_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge);
+
+void canque_ends_free_rtl(struct canque_ends_t *qends);
+
+int canqueue_ends_init_rtl(struct canque_ends_t *qends);
+
+int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync);
+
+#else /*CAN_WITH_RTL*/
+
+static inline int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
+                       struct canque_edge_t *qedge, int what) { return 0; }
+
+#endif /*CAN_WITH_RTL*/
+
+
+#endif /*_CAN_QUEUE_H*/
diff --git a/embedded/app/usbcan/can/can_sysdep.h b/embedded/app/usbcan/can/can_sysdep.h
new file mode 100644 (file)
index 0000000..5a3b86c
--- /dev/null
@@ -0,0 +1,226 @@
+/* can_sysdep.h - hides differences between individual Linux kernel 
+ *                versions and RT extensions 
+ * Linux CAN-bus device driver.
+ * Written by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef _CAN_SYSDEP_H
+#define _CAN_SYSDEP_H
+
+#ifdef CAN_WITH_RTL
+#include <rtl.h>
+#include <rtl_sync.h>
+#include <rtl_core.h>
+#include <rtl_mutex.h>
+#include <rtl_sched.h>
+#include <time.h>
+#endif /*CAN_WITH_RTL*/
+
+/*#define __NO_VERSION__*/
+/*#include <linux/module.h>*/
+
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/errno.h>
+
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "lincan_config.h"
+
+/*optional features*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
+#define CAN_ENABLE_KERN_FASYNC
+#ifdef CONFIG_PCI
+#define CAN_ENABLE_PCI_SUPPORT
+#endif
+#ifdef CONFIG_OC_LINCANVME
+#define CAN_ENABLE_VME_SUPPORT
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+#include <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+
+#ifdef CAN_ENABLE_PCI_SUPPORT
+#include "linux/pci.h"
+#endif /*CAN_ENABLE_PCI_SUPPORT*/
+
+/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
+   kernels need next definitions  too */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
+  #define wait_queue_head_t struct wait_queue *
+  #define wait_queue_t      struct wait_queue
+  #define init_waitqueue_head(queue_head) (*queue_head=NULL)
+  #define init_waitqueue_entry(qentry,qtask) \
+                        (qentry->next=NULL,qentry->task=qtask)
+  #define DECLARE_WAIT_QUEUE_HEAD(name) \
+        struct wait_queue * name=NULL
+  #define DECLARE_WAITQUEUE(wait, current) \
+        struct wait_queue wait = { current, NULL }
+  #define init_MUTEX(sem) (*sem=MUTEX)
+  #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
+#endif /* 2.2.19 */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) && !defined(DECLARE_TASKLET)
+  #define tasklet_struct tq_struct
+  #define DECLARE_TASKLET(_name, _func, _data) \
+                struct tq_struct _name = { sync: 0, routine: _func, data: (void*)_data }
+
+  /* void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); */
+  #define tasklet_init(_tasklet, _func, _data) \
+    do{ \
+       /* (_tasklet)->next=NULL; */ \
+       /* Above not needed for 2.2.x and buggy for 2.4.x */ \
+       (_tasklet)->sync=0; \
+       (_tasklet)->routine=_func; \
+       (_tasklet)->data=(void*)_data; \
+    }while(0)
+
+  /* void tasklet_schedule(struct tasklet_struct *t) */
+  #define tasklet_schedule(_tasklet) \
+    do{ \
+       queue_task(_tasklet,&tq_immediate); \
+       mark_bh(IMMEDIATE_BH); \
+    }while(0)
+
+  /* void tasklet_kill(struct tasklet_struct *t); */
+  #define tasklet_kill(_tasklet) \
+                synchronize_irq()
+
+#endif /* 2.4.0 */
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+
+#define MINOR_NR \
+       (MINOR(file->f_dentry->d_inode->i_rdev))
+
+#else /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+#define MINOR_NR \
+       (minor(file->f_dentry->d_inode->i_rdev))
+
+#endif /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+#ifndef CAN_WITH_RTL
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL))
+  typedef void can_irqreturn_t;
+  #define CAN_IRQ_NONE
+  #define CAN_IRQ_HANDLED
+  #define CAN_IRQ_RETVAL(x)
+#else /* <=2.5.67 */
+  typedef irqreturn_t can_irqreturn_t;
+  #define CAN_IRQ_NONE    IRQ_NONE
+  #define CAN_IRQ_HANDLED IRQ_HANDLED
+  #define CAN_IRQ_RETVAL  IRQ_RETVAL
+#endif /* <=2.5.67 */
+#else /*CAN_WITH_RTL*/
+  typedef int can_irqreturn_t;
+  #define CAN_IRQ_NONE        0
+  #define CAN_IRQ_HANDLED     1
+  #define CAN_IRQ_RETVAL(x)   ((x) != 0)
+#endif /*CAN_WITH_RTL*/
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33))
+   #define can_synchronize_irq(irqnum) synchronize_irq()
+#else /* >=2.5.33 */
+   #define can_synchronize_irq synchronize_irq
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+  #define del_timer_sync del_timer
+#endif /* <2.4.0 */
+
+#ifdef __HAVE_ARCH_CMPXCHG
+  #define CAN_HAVE_ARCH_CMPXCHG
+#endif
+
+#ifndef CAN_WITH_RTL
+/* Standard LINUX kernel */
+
+#define can_spinlock_t             spinlock_t
+#define can_spin_irqflags_t        unsigned long
+#define can_spin_lock              spin_lock
+#define can_spin_unlock            spin_unlock
+#define can_spin_lock_irqsave      spin_lock_irqsave
+#define can_spin_unlock_irqrestore spin_unlock_irqrestore
+#define can_spin_lock_init         spin_lock_init
+
+#ifndef DEFINE_SPINLOCK
+#define CAN_DEFINE_SPINLOCK(x)     can_spinlock_t x = SPIN_LOCK_UNLOCKED
+#else /*DEFINE_SPINLOCK*/
+#define CAN_DEFINE_SPINLOCK        DEFINE_SPINLOCK
+#endif /*DEFINE_SPINLOCK*/
+
+#if defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+#define can_preempt_disable        preempt_disable
+#define can_preempt_enable         preempt_enable
+#else /*CONFIG_PREEMPT*/
+#define can_preempt_disable()      do { } while (0)
+#define can_preempt_enable()       do { } while (0)
+#endif /*CONFIG_PREEMPT*/
+
+#define can_enable_irq             enable_irq
+#define can_disable_irq            disable_irq
+
+#define can_printk                 printk
+
+/* CAN message timestamp source, it is called from interrupt context */
+#define can_gettimeofday do_gettimeofday
+
+#else /*CAN_WITH_RTL*/
+
+#define can_spinlock_t             rtl_spinlock_t
+#define can_spin_irqflags_t        rtl_irqstate_t
+#define can_spin_lock              rtl_spin_lock
+#define can_spin_unlock            rtl_spin_unlock
+#define can_spin_lock_irqsave      rtl_spin_lock_irqsave
+#define can_spin_unlock_irqrestore rtl_spin_unlock_irqrestore
+#define can_spin_lock_init         rtl_spin_lock_init
+
+#define CAN_DEFINE_SPINLOCK(x)     can_spinlock_t x = SPIN_LOCK_UNLOCKED
+
+#define can_preempt_disable()      do { } while (0)
+#define can_preempt_enable()       do { } while (0)
+
+#define can_enable_irq             rtl_hard_enable_irq
+#define can_disable_irq            rtl_hard_disable_irq
+
+#define can_printk                 rtl_printf
+
+/*
+ * terrible hack to test rtl_file private_data concept, ugh !!!
+ * this would result in crash on architectures,  where 
+ * sizeof(int) < sizeof(void *)
+ */
+#define can_set_rtl_file_private_data(fptr, p) do{ fptr->f_minor=(long)(p); } while(0)
+#define can_get_rtl_file_private_data(fptr) ((void*)((fptr)->f_minor))
+
+extern can_spinlock_t can_irq_manipulation_lock;
+
+/* CAN message timestamp source, it is called from interrupt context */
+#define can_gettimeofday(ptr) do {\
+         struct timespec temp_timespec;\
+         clock_gettime(CLOCK_REALTIME,&temp_timespec);\
+         ptr->tv_usec=temp_timespec.tv_nsec/1000;\
+         ptr->tv_sec=temp_timespec.tv_sec;\
+       } while(0)
+
+#endif /*CAN_WITH_RTL*/
+
+#endif /*_CAN_SYSDEP_H*/
diff --git a/embedded/app/usbcan/can/can_sysless.h b/embedded/app/usbcan/can/can_sysless.h
new file mode 100644 (file)
index 0000000..af3d703
--- /dev/null
@@ -0,0 +1,537 @@
+/* can_sysdep.h - hides differences between individual Linux kernel
+ *                versions and RT extensions
+ * Linux CAN-bus device driver.
+ * Written by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef _CAN_SYSDEP_H
+#define _CAN_SYSDEP_H
+
+#ifdef CAN_WITH_RTL
+#include <rtl.h>
+#include <rtl_sync.h>
+#include <rtl_core.h>
+#include <rtl_mutex.h>
+#include <rtl_sched.h>
+#include <time.h>
+#endif /*CAN_WITH_RTL*/
+
+#include <cpu_def.h>
+#include <malloc.h>
+
+// typedef unsigned long atomic_t;
+typedef struct { volatile int counter; } atomic_t;
+
+#define mb()   __memory_barrier()
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                     \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+/*#define __NO_VERSION__*/
+/*#include <linux/module.h>*/
+
+// #include <linux/version.h>
+// #include <linux/wait.h>
+// #include <linux/list.h>
+// #include <linux/fs.h>
+// #include <linux/ioport.h>
+// #include <linux/delay.h>
+// #include <linux/sched.h>
+// #include <linux/interrupt.h>
+// #include <asm/errno.h>
+//
+// #include <asm/io.h>
+// #include <asm/atomic.h>
+// #include <asm/irq.h>
+// #include <asm/uaccess.h>
+
+// #include "lincan_config.h"
+
+/*optional features*/
+// #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
+// #define CAN_ENABLE_KERN_FASYNC
+// #ifdef CONFIG_PCI
+// #define CAN_ENABLE_PCI_SUPPORT
+// #endif
+// #ifdef CONFIG_OC_LINCANVME
+// #define CAN_ENABLE_VME_SUPPORT
+// #endif
+// #endif
+
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+// #include <linux/malloc.h>
+// #else
+// #include <linux/slab.h>
+// #endif
+
+// #ifdef CAN_ENABLE_PCI_SUPPORT
+// #include "linux/pci.h"
+// #endif /*CAN_ENABLE_PCI_SUPPORT*/
+
+/* Next is not sctrictly correct, because of 2.3.0, 2.3.1, 2.3.2
+   kernels need next definitions  too */
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)) /* may need correction */
+   #define wait_queue_head_t struct wait_queue *
+   #define wait_queue_t      struct wait_queue
+   #define init_waitqueue_head(queue_head) (*queue_head=NULL)
+  #define init_waitqueue_entry(qentry,qtask) \
+                        (qentry->next=NULL,qentry->task=qtask)
+  #define DECLARE_WAIT_QUEUE_HEAD(name) \
+        struct wait_queue * name=NULL
+  #define DECLARE_WAITQUEUE(wait, current) \
+        struct wait_queue wait = { current, NULL }
+//   #define init_MUTEX(sem) (*sem=MUTEX)
+//   #define DECLARE_MUTEX(name) struct semaphore name=MUTEX
+// #endif /* 2.2.19 */
+
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) && !defined(DECLARE_TASKLET)
+//   #define tasklet_struct tq_struct
+/*  #define DECLARE_TASKLET(_name, _func, _data) \
+                struct tq_struct _name = { sync: 0, routine: _func, data: (void*)_data }*/
+//
+//   /* void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); */
+/*   #define tasklet_init(_tasklet, _func, _data) \
+    do{ \
+       (_tasklet)->sync=0; \
+       (_tasklet)->routine=_func; \
+       (_tasklet)->data=(void*)_data; \
+    }while(0)*/
+//
+//   /* void tasklet_schedule(struct tasklet_struct *t) */
+/*  #define tasklet_schedule(_tasklet) \
+    do{ \
+       queue_task(_tasklet,&tq_immediate); \
+       mark_bh(IMMEDIATE_BH); \
+    }while(0)*/
+//
+//   /* void tasklet_kill(struct tasklet_struct *t); */
+/*  #define tasklet_kill(_tasklet) \
+                synchronize_irq()*/
+//
+// #endif /* 2.4.0 */
+
+
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+
+#define MINOR_NR \
+       (MINOR(file->f_dentry->d_inode->i_rdev))
+
+// #else /* Linux kernel < 2.5.7 or >= 2.6.0 */
+//
+/*#define MINOR_NR \
+       (minor(file->f_dentry->d_inode->i_rdev))*/
+//
+// #endif /* Linux kernel < 2.5.7 or >= 2.6.0 */
+
+// #ifndef CAN_WITH_RTL
+// #if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) && !defined(IRQ_RETVAL))
+  typedef void can_irqreturn_t;
+  #define CAN_IRQ_NONE
+  #define CAN_IRQ_HANDLED
+  #define CAN_IRQ_RETVAL(x)
+// #else /* <=2.5.67 */
+//   typedef irqreturn_t can_irqreturn_t;
+//   #define CAN_IRQ_NONE    IRQ_NONE
+//   #define CAN_IRQ_HANDLED IRQ_HANDLED
+//   #define CAN_IRQ_RETVAL  IRQ_RETVAL
+// #endif /* <=2.5.67 */
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+/*  #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \
+               int irq_number, void *dev_id, struct pt_regs *regs*/
+// #else /* < 2.6.19 */
+  #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \
+               int irq_number, void *dev_id
+// #endif /* < 2.6.19 */
+// #else /*CAN_WITH_RTL*/
+//   typedef int can_irqreturn_t;
+//   #define CAN_IRQ_NONE        0
+//   #define CAN_IRQ_HANDLED     1
+//   #define CAN_IRQ_RETVAL(x)   ((x) != 0)
+/*  #define CAN_IRQ_HANDLER_ARGS(irq_number, dev_id) \
+               int irq_number, void *dev_id, struct pt_regs *regs*/
+// #endif /*CAN_WITH_RTL*/
+
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,33))
+//    #define can_synchronize_irq(irqnum) synchronize_irq()
+// #else /* >=2.5.33 */
+   #define can_synchronize_irq synchronize_irq
+// #endif
+
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
+//   #define del_timer_sync del_timer
+// #endif /* <2.4.0 */
+
+// #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+   typedef unsigned long can_ioptr_t;
+   #define can_ioptr2ulong(ioaddr) ((unsigned long)(ioaddr))
+   #define can_ulong2ioptr(addr)   ((unsigned long)(addr))
+   #define can_inb(ioaddr) inb(ioaddr)
+   #define can_outb(data,ioaddr) outb(data,ioaddr)
+   #define can_inw(ioaddr) inb(ioaddr)
+   #define can_outw(data,ioaddr) outb(data,ioaddr)
+   #define can_inl(ioaddr) inb(ioaddr)
+   #define can_outl(data,ioaddr) outb(data,ioaddr)
+// #else /* >=2.6.9 */
+//    typedef void __iomem * can_ioptr_t;
+//    #define can_ioptr2ulong(ioaddr) ((unsigned long __force)(ioaddr))
+//    #define can_ulong2ioptr(addr)   ((can_ioptr_t)(addr))
+//    #define can_inb(ioaddr) inb(can_ioptr2ulong(ioaddr))
+//    #define can_outb(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr))
+//    #define can_inw(ioaddr) inb(can_ioptr2ulong(ioaddr))
+//    #define can_outw(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr))
+//    #define can_inl(ioaddr) inb(can_ioptr2ulong(ioaddr))
+//    #define can_outl(data,ioaddr) outb(data,can_ioptr2ulong(ioaddr))
+// #endif
+
+#define can_readb  readb
+#define can_writeb writeb
+#define can_readw  readw
+#define can_writew writew
+#define can_readl  readl
+#define can_writel writel
+
+#define can_ioport2ioptr can_ulong2ioptr
+
+#ifdef __HAVE_ARCH_CMPXCHG
+  #define CAN_HAVE_ARCH_CMPXCHG
+#endif
+
+// #ifndef CAN_WITH_RTL
+/* Standard LINUX kernel */
+
+#define can_spinlock_t             long
+#define can_spin_irqflags_t        unsigned long
+#define can_spin_lock(lock)        cli()
+#define can_spin_unlock(lock)      sti()
+#define can_spin_lock_irqsave(lock,flags)      save_and_cli(flags)
+#define can_spin_unlock_irqrestore(lock,flags) restore_flags(flags)
+#define can_spin_lock_init         can_splck_init
+
+#define CAN_DEFINE_SPINLOCK(x)     can_spinlock_t x = 0
+
+static inline
+void can_splck_init(can_spinlock_t *x)
+{
+       *x=0;
+}
+
+// #if !defined(CONFIG_PREEMPT_RT) && ( defined(CONFIG_PREEMPT) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) )
+// #define can_preempt_disable        preempt_disable
+// #define can_preempt_enable         preempt_enable
+// #else /*CONFIG_PREEMPT*/
+#define can_preempt_disable()      do { } while (0)
+#define can_preempt_enable()       do { } while (0)
+// #endif /*CONFIG_PREEMPT*/
+
+// #define can_enable_irq             sti()
+// #define can_disable_irq            cli()
+#define can_enable_irq(var)           (var=1)
+#define can_disable_irq(var)          (var=0)
+
+#define can_printk                 printf
+#define KERN_CRIT
+#define KERN_ERR
+
+/// LINUX src: include/asm-arm/bitops.h
+
+#define set_bit ____atomic_set_bit
+#define clear_bit ____atomic_clear_bit
+#define change_bit ____atomic_change_bit
+#define test_and_set_bit ____atomic_test_and_set_bit
+#define test_and_clear_bit ____atomic_test_and_clear_bit
+#define test_and_change_bit ____atomic_test_and_change_bit
+#define raw_local_irq_save(flags) save_and_cli(flags);
+#define raw_local_irq_restore(flags) restore_flags(flags);
+/*
+ * These functions are the basis of our bit ops.
+ *
+ * First, the atomic bitops. These use native endian.
+ */
+static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long flags;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       raw_local_irq_save(flags);
+       *p |= mask;
+       raw_local_irq_restore(flags);
+}
+
+static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long flags;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       raw_local_irq_save(flags);
+       *p &= ~mask;
+       raw_local_irq_restore(flags);
+}
+
+static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long flags;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       raw_local_irq_save(flags);
+       *p ^= mask;
+       raw_local_irq_restore(flags);
+}
+
+static inline int
+____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long flags;
+       unsigned int res;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       raw_local_irq_save(flags);
+       res = *p;
+       *p = res | mask;
+       raw_local_irq_restore(flags);
+
+       return res & mask;
+}
+
+static inline int
+____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long flags;
+       unsigned int res;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       raw_local_irq_save(flags);
+       res = *p;
+       *p = res & ~mask;
+       raw_local_irq_restore(flags);
+
+       return res & mask;
+}
+
+static inline int
+____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long flags;
+       unsigned int res;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       raw_local_irq_save(flags);
+       res = *p;
+       *p = res ^ mask;
+       raw_local_irq_restore(flags);
+
+       return res & mask;
+}
+
+/// LINUX src: include/asm-arm/atomic.h
+
+#define atomic_read(v) ((v)->counter)
+
+#define atomic_set(v,i)        (((v)->counter) = (i))
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+       unsigned long flags;
+       int val;
+
+       raw_local_irq_save(flags);
+       val = v->counter;
+       v->counter = val += i;
+       raw_local_irq_restore(flags);
+
+       return val;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+       unsigned long flags;
+       int val;
+
+       raw_local_irq_save(flags);
+       val = v->counter;
+       v->counter = val -= i;
+       raw_local_irq_restore(flags);
+
+       return val;
+}
+
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       int ret;
+       unsigned long flags;
+
+       raw_local_irq_save(flags);
+       ret = v->counter;
+       if (ret == old)
+               v->counter = new;
+       raw_local_irq_restore(flags);
+
+       return ret;
+}
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+       int c, old;
+
+       c = atomic_read(v);
+       while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+               c = old;
+       return c != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+#define atomic_add(i, v)       (void) atomic_add_return(i, v)
+#define atomic_inc(v)          (void) atomic_add_return(1, v)
+#define atomic_sub(i, v)       (void) atomic_sub_return(i, v)
+#define atomic_dec(v)          (void) atomic_sub_return(1, v)
+
+#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
+#define atomic_inc_return(v)    (atomic_add_return(1, v))
+#define atomic_dec_return(v)    (atomic_sub_return(1, v))
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+
+#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
+
+/* Atomic operations are already serializing on ARM */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec()     barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc()     barrier()
+
+/// LINUX src: include/linux/interrupt.h
+
+#define ATOMIC_INIT(i) { (i) }
+
+/* Tasklets --- multithreaded analogue of BHs.
+
+   Main feature differing them of generic softirqs: tasklet
+   is running only on one CPU simultaneously.
+
+   Main feature differing them of BHs: different tasklets
+   may be run simultaneously on different CPUs.
+
+   Properties:
+   * If tasklet_schedule() is called, then tasklet is guaranteed
+     to be executed on some cpu at least once after this.
+   * If the tasklet is already scheduled, but its excecution is still not
+     started, it will be executed only once.
+   * If this tasklet is already running on another CPU (or schedule is called
+     from tasklet itself), it is rescheduled for later.
+   * Tasklet is strictly serialized wrt itself, but not
+     wrt another tasklets. If client needs some intertask synchronization,
+     he makes it with spinlocks.
+ */
+
+struct tasklet_struct
+{
+       struct tasklet_struct *next;
+       unsigned long state;
+       atomic_t count;
+       void (*func)(unsigned long);
+       unsigned long data;
+};
+
+#define DECLARE_TASKLET(name, func, data) \
+struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
+
+#define DECLARE_TASKLET_DISABLED(name, func, data) \
+struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
+
+/* CAN message timestamp source, it is called from interrupt context */
+//#define can_gettimeofday do_gettimeofday
+
+/// from linux/timer.h
+
+struct tvec_t_base_s;
+
+struct timer_list {
+       struct list_head entry;
+       unsigned long expires;
+
+       void (*function)(unsigned long);
+       unsigned long data;
+
+       struct tvec_t_base_s *base;
+#ifdef CONFIG_TIMER_STATS
+       void *start_site;
+       char start_comm[16];
+       int start_pid;
+#endif
+};
+
+static inline void udelay(long time)
+{
+       volatile long ticks=(time * CCLK) / 2000000;
+       do{
+               ticks--;
+       }
+       while(ticks>0);
+}
+
+// #else /*CAN_WITH_RTL*/
+//
+// #define can_spinlock_t             long
+// #define can_spin_irqflags_t        unsigned long
+// #define can_spin_lock              save_and_cli
+// #define can_spin_unlock            restore_flags
+// #define can_spin_lock_irqsave      save_and_cli
+// #define can_spin_unlock_irqrestore restore_flags
+// #define can_spin_lock_init         can_splck_init
+//
+// #define CAN_DEFINE_SPINLOCK(x)     can_spinlock_t x = 0
+//
+// #define can_preempt_disable()      do { } while (0)
+// #define can_preempt_enable()       do { } while (0)
+//
+// #define can_enable_irq             sti
+// #define can_disable_irq            cli
+//
+// #define can_printk                 rtl_printf
+//
+// /*
+//  * terrible hack to test rtl_file private_data concept, ugh !!!
+//  * this would result in crash on architectures,  where
+//  * sizeof(int) < sizeof(void *)
+//  */
+// #define can_set_rtl_file_private_data(fptr, p) do{ fptr->f_minor=(long)(p); } while(0)
+// #define can_get_rtl_file_private_data(fptr) ((void*)((fptr)->f_minor))
+//
+// extern can_spinlock_t can_irq_manipulation_lock;
+//
+// /* CAN message timestamp source, it is called from interrupt context */
+/*#define can_gettimeofday(ptr) do {\
+         struct timespec temp_timespec;\
+         clock_gettime(CLOCK_REALTIME,&temp_timespec);\
+         ptr->tv_usec=temp_timespec.tv_nsec/1000;\
+         ptr->tv_sec=temp_timespec.tv_sec;\
+       } while(0)*/
+//
+// #endif /*CAN_WITH_RTL*/
+
+#endif /*_CAN_SYSDEP_H*/
diff --git a/embedded/app/usbcan/can/canmsg.h b/embedded/app/usbcan/can/canmsg.h
new file mode 100644 (file)
index 0000000..779f68c
--- /dev/null
@@ -0,0 +1,136 @@
+/* canmsg.h - common kernel-space and user-space CAN message structure
+ * Linux CAN-bus device driver.
+ * Written by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef _CANMSG_T_H
+#define _CANMSG_T_H
+
+#ifdef __KERNEL__
+
+#include <linux/time.h>
+#include <linux/types.h>
+
+#else /* __KERNEL__ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#endif /* __KERNEL__ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 
+ * CAN_MSG_VERSION_2 enables new canmsg_t layout compatible with
+ * can4linux project from http://www.port.de/
+ * 
+ */
+#define CAN_MSG_VERSION_2
+
+/* Number of data bytes in one CAN message */
+#define CAN_MSG_LENGTH 8
+
+#ifdef CAN_MSG_VERSION_2
+
+typedef struct timeval canmsg_tstamp_t ;
+
+typedef unsigned long canmsg_id_t;
+
+/**
+ * struct canmsg_t - structure representing CAN message
+ * @flags:  message flags
+ *      %MSG_RTR .. message is Remote Transmission Request,
+ *     %MSG_EXT .. message with extended ID, 
+ *      %MSG_OVR .. indication of queue overflow condition,
+ *     %MSG_LOCAL .. message originates from this node.
+ * @cob:    communication object number (not used)
+ * @id:     ID of CAN message
+ * @timestamp: not used
+ * @length: length of used data
+ * @data:   data bytes buffer
+ *
+ * Header: canmsg.h
+ */
+struct canmsg_t {
+       int             flags;
+       int             cob;
+       canmsg_id_t     id;
+       canmsg_tstamp_t timestamp;
+       unsigned short  length;
+       unsigned char   data[CAN_MSG_LENGTH];
+};
+
+#else /*CAN_MSG_VERSION_2*/
+#ifndef PACKED
+#define PACKED __attribute__((packed))
+#endif
+/* Old, deprecated version of canmsg_t structure */
+struct canmsg_t {
+       short           flags;
+       int             cob;
+       canmsg_id_t     id;
+       unsigned long   timestamp;
+       unsigned int    length;
+       unsigned char   data[CAN_MSG_LENGTH];
+} PACKED;
+#endif /*CAN_MSG_VERSION_2*/
+
+typedef struct canmsg_t canmsg_t;
+
+/**
+ * struct canfilt_t - structure for acceptance filter setup
+ * @flags:  message flags
+ *      %MSG_RTR .. message is Remote Transmission Request,
+ *     %MSG_EXT .. message with extended ID, 
+ *      %MSG_OVR .. indication of queue overflow condition,
+ *     %MSG_LOCAL .. message originates from this node.
+ *     there are corresponding mask bits
+ *     %MSG_RTR_MASK, %MSG_EXT_MASK, %MSG_LOCAL_MASK.
+ *     %MSG_PROCESSLOCAL enables local messages processing in the
+ *     combination with global setting
+ * @queid:  CAN queue identification in the case of the multiple
+ *         queues per one user (open instance)
+ * @cob:    communication object number (not used)
+ * @id:     selected required value of cared ID id bits
+ * @mask:   select bits significand for the comparation;
+ *          1 .. take care about corresponding ID bit, 0 .. don't care
+ *
+ * Header: canmsg.h
+ */
+struct canfilt_t {
+       int             flags;
+       int             queid;
+       int             cob;
+       canmsg_id_t     id;
+       canmsg_id_t     mask;
+};
+
+typedef struct canfilt_t canfilt_t;
+
+/* Definitions to use for canmsg_t and canfilt_t flags */
+#define MSG_RTR   (1<<0)
+#define MSG_OVR   (1<<1)
+#define MSG_EXT   (1<<2)
+#define MSG_LOCAL (1<<3)
+/* If you change above lines, check canque_filtid2internal function */
+
+/* Additional definitions used for canfilt_t only */
+#define MSG_FILT_MASK_SHIFT   8
+#define MSG_RTR_MASK   (MSG_RTR<<MSG_FILT_MASK_SHIFT)
+#define MSG_EXT_MASK   (MSG_EXT<<MSG_FILT_MASK_SHIFT)
+#define MSG_LOCAL_MASK (MSG_LOCAL<<MSG_FILT_MASK_SHIFT)
+#define MSG_PROCESSLOCAL (MSG_OVR<<MSG_FILT_MASK_SHIFT)
+
+/* Can message ID mask */
+#define MSG_ID_MASK ((1l<<29)-1)
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /*_CANMSG_T_H*/
diff --git a/embedded/app/usbcan/can/constants.h b/embedded/app/usbcan/can/constants.h
new file mode 100644 (file)
index 0000000..8ba9ba4
--- /dev/null
@@ -0,0 +1,113 @@
+/* constants.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef __CONSTANTS_H__
+#define __CONSTANTS_H__
+
+/* Device name as it will appear in /proc/devices */
+#define DEVICE_NAME "can"
+
+/* Branch of the driver */
+#define CAN_DRV_BRANCH (('L'<<24)|('I'<<16)|('N'<<8)|'C')
+
+/* Version of the driver */
+#define CAN_DRV_VER_MAJOR 0
+#define CAN_DRV_VER_MINOR 3
+#define CAN_DRV_VER_PATCH 3
+#define CAN_DRV_VER ((CAN_DRV_VER_MAJOR<<16) | (CAN_DRV_VER_MINOR<<8) | CAN_DRV_VER_PATCH)
+
+/* Default driver major number, see /usr/src/linux/Documentation/devices.txt */
+#define CAN_MAJOR 91
+
+/* Definition of the maximum number of concurrent supported hardware boards,
+ * chips per board, total number of chips, interrupts and message objects.
+ * Obviously there are no 32 different interrupts, but each chip can have its
+ * own interrupt so we have to check for it MAX_IRQ == MAX_TOT_CHIPS times.
+ */
+#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 32
+#define MAX_TOT_MSGOBJS (MAX_TOT_CHIPS*MAX_MSGOBJS)
+#define MAX_BUF_LENGTH 64
+//#define MAX_BUF_LENGTH 4
+
+
+/* These flags can be used for the msgobj_t structure flags data entry */
+#define MSGOBJ_OPENED_b                   0
+#define MSGOBJ_TX_REQUEST_b       1
+#define MSGOBJ_TX_LOCK_b           2
+#define MSGOBJ_IRQ_REQUEST_b       3
+#define MSGOBJ_WORKER_WAKE_b       4
+#define MSGOBJ_FILTCH_REQUEST_b    5
+#define MSGOBJ_RX_MODE_b           6
+#define MSGOBJ_RX_MODE_EXT_b       7
+#define MSGOBJ_TX_PENDING_b        8
+
+#define MSGOBJ_OPENED              (1<<MSGOBJ_OPENED_b)
+#define MSGOBJ_TX_REQUEST          (1<<MSGOBJ_TX_REQUEST_b)
+#define MSGOBJ_TX_LOCK             (1<<MSGOBJ_TX_LOCK_b)
+#define MSGOBJ_IRQ_REQUEST         (1<<MSGOBJ_IRQ_REQUEST_b)
+#define MSGOBJ_WORKER_WAKE         (1<<MSGOBJ_WORKER_WAKE_b)
+#define MSGOBJ_FILTCH_REQUEST      (1<<MSGOBJ_FILTCH_REQUEST_b)
+#define MSGOBJ_RX_MODE             (1<<MSGOBJ_RX_MODE_b)
+#define MSGOBJ_RX_MODE_EXT         (1<<MSGOBJ_RX_MODE_EXT_b)
+#define MSGOBJ_TX_PENDING          (1<<MSGOBJ_TX_PENDING_b)
+
+#define can_msgobj_test_fl(obj,obj_fl) \
+  test_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_set_fl(obj,obj_fl) \
+  set_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_clear_fl(obj,obj_fl) \
+  clear_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_test_and_set_fl(obj,obj_fl) \
+  test_and_set_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+#define can_msgobj_test_and_clear_fl(obj,obj_fl) \
+  test_and_clear_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
+
+
+/* These flags can be used for the canchip_t structure flags data entry */
+#define CHIP_ATTACHED    (1<<0)  /* chip is attached to HW, release_chip() has to be called */
+#define CHIP_CONFIGURED  (1<<1)  /* chip is configured and prepared for communication */
+#define CHIP_SEGMENTED   (1<<2)  /* segmented access, ex: i82527 with 16 byte window*/
+#define CHIP_IRQ_SETUP   (1<<3)  /* IRQ handler has been set */
+#define CHIP_IRQ_PCI     (1<<4)  /* chip is on PCI board and uses PCI interrupt  */
+#define CHIP_IRQ_VME     (1<<5)  /* interrupt is VME bus and requires VME bridge */
+#define CHIP_IRQ_CUSTOM  (1<<6)  /* custom interrupt provided by board or chip code */
+#define CHIP_IRQ_FAST    (1<<7)  /* interrupt handler only schedules postponed processing */
+
+#define CHIP_MAX_IRQLOOP 1000
+
+/* System independent defines of IRQ handled state */
+#define CANCHIP_IRQ_NONE     0
+#define CANCHIP_IRQ_HANDLED  1
+#define CANCHIP_IRQ_ACCEPTED 2
+#define CANCHIP_IRQ_STUCK    3
+
+/* These flags can be used for the candevices_t structure flags data entry */
+#define CANDEV_PROGRAMMABLE_IRQ (1<<0)
+#define CANDEV_IO_RESERVED     (1<<1)
+
+/* Next flags are specific for struct canuser_t applications connection */
+#define CANUSER_RTL_CLIENT      (1<<0)
+#define CANUSER_RTL_MEM         (1<<1)
+#define CANUSER_DIRECT          (1<<2)
+
+
+enum timing_BTR1 {
+       MAX_TSEG1 = 15,
+       MAX_TSEG2 = 7
+};
+
+/* Flags for baud_rate function */
+#define BTR1_SAM (1<<1)
+
+#endif
diff --git a/embedded/app/usbcan/can/devcommon.h b/embedded/app/usbcan/can/devcommon.h
new file mode 100644 (file)
index 0000000..837ffb6
--- /dev/null
@@ -0,0 +1,15 @@
+/* devcommon.h - common device code
+ * Linux CAN-bus device driver.
+ * New CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./canmsg.h"
+#include "./can_sysdep.h"
+#include "./constants.h"
+#include "./can_queue.h"
+
+int canqueue_ends_init_chip(struct canque_ends_t *qends, struct canchip_t *chip, struct msgobj_t *obj);
+int canqueue_ends_done_chip(struct canque_ends_t *qends);
diff --git a/embedded/app/usbcan/can/errno-base.h b/embedded/app/usbcan/can/errno-base.h
new file mode 100755 (executable)
index 0000000..6511597
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _ASM_GENERIC_ERRNO_BASE_H
+#define _ASM_GENERIC_ERRNO_BASE_H
+
+#define        EPERM            1      /* Operation not permitted */
+#define        ENOENT           2      /* No such file or directory */
+#define        ESRCH            3      /* No such process */
+#define        EINTR            4      /* Interrupted system call */
+#define        EIO              5      /* I/O error */
+#define        ENXIO            6      /* No such device or address */
+#define        E2BIG            7      /* Argument list too long */
+#define        ENOEXEC          8      /* Exec format error */
+#define        EBADF            9      /* Bad file number */
+#define        ECHILD          10      /* No child processes */
+#define        EAGAIN          11      /* Try again */
+#define        ENOMEM          12      /* Out of memory */
+#define        EACCES          13      /* Permission denied */
+#define        EFAULT          14      /* Bad address */
+#define        ENOTBLK         15      /* Block device required */
+#define        EBUSY           16      /* Device or resource busy */
+#define        EEXIST          17      /* File exists */
+#define        EXDEV           18      /* Cross-device link */
+#define        ENODEV          19      /* No such device */
+#define        ENOTDIR         20      /* Not a directory */
+#define        EISDIR          21      /* Is a directory */
+#define        EINVAL          22      /* Invalid argument */
+#define        ENFILE          23      /* File table overflow */
+#define        EMFILE          24      /* Too many open files */
+#define        ENOTTY          25      /* Not a typewriter */
+#define        ETXTBSY         26      /* Text file busy */
+#define        EFBIG           27      /* File too large */
+#define        ENOSPC          28      /* No space left on device */
+#define        ESPIPE          29      /* Illegal seek */
+#define        EROFS           30      /* Read-only file system */
+#define        EMLINK          31      /* Too many links */
+#define        EPIPE           32      /* Broken pipe */
+#define        EDOM            33      /* Math argument out of domain of func */
+#define        ERANGE          34      /* Math result not representable */
+
+#endif
diff --git a/embedded/app/usbcan/can/errno.h b/embedded/app/usbcan/can/errno.h
new file mode 100755 (executable)
index 0000000..6edbe36
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _ASM_GENERIC_ERRNO_H
+#define _ASM_GENERIC_ERRNO_H
+
+#include "./errno-base.h"
+
+#define        EDEADLK         35      /* Resource deadlock would occur */
+#define        ENAMETOOLONG    36      /* File name too long */
+#define        ENOLCK          37      /* No record locks available */
+#define        ENOSYS          38      /* Function not implemented */
+#define        ENOTEMPTY       39      /* Directory not empty */
+#define        ELOOP           40      /* Too many symbolic links encountered */
+#define        EWOULDBLOCK     EAGAIN  /* Operation would block */
+#define        ENOMSG          42      /* No message of desired type */
+#define        EIDRM           43      /* Identifier removed */
+#define        ECHRNG          44      /* Channel number out of range */
+#define        EL2NSYNC        45      /* Level 2 not synchronized */
+#define        EL3HLT          46      /* Level 3 halted */
+#define        EL3RST          47      /* Level 3 reset */
+#define        ELNRNG          48      /* Link number out of range */
+#define        EUNATCH         49      /* Protocol driver not attached */
+#define        ENOCSI          50      /* No CSI structure available */
+#define        EL2HLT          51      /* Level 2 halted */
+#define        EBADE           52      /* Invalid exchange */
+#define        EBADR           53      /* Invalid request descriptor */
+#define        EXFULL          54      /* Exchange full */
+#define        ENOANO          55      /* No anode */
+#define        EBADRQC         56      /* Invalid request code */
+#define        EBADSLT         57      /* Invalid slot */
+
+#define        EDEADLOCK       EDEADLK
+
+#define        EBFONT          59      /* Bad font file format */
+#define        ENOSTR          60      /* Device not a stream */
+#define        ENODATA         61      /* No data available */
+#define        ETIME           62      /* Timer expired */
+#define        ENOSR           63      /* Out of streams resources */
+#define        ENONET          64      /* Machine is not on the network */
+#define        ENOPKG          65      /* Package not installed */
+#define        EREMOTE         66      /* Object is remote */
+#define        ENOLINK         67      /* Link has been severed */
+#define        EADV            68      /* Advertise error */
+#define        ESRMNT          69      /* Srmount error */
+#define        ECOMM           70      /* Communication error on send */
+#define        EPROTO          71      /* Protocol error */
+#define        EMULTIHOP       72      /* Multihop attempted */
+#define        EDOTDOT         73      /* RFS specific error */
+#define        EBADMSG         74      /* Not a data message */
+#define        EOVERFLOW       75      /* Value too large for defined data type */
+#define        ENOTUNIQ        76      /* Name not unique on network */
+#define        EBADFD          77      /* File descriptor in bad state */
+#define        EREMCHG         78      /* Remote address changed */
+#define        ELIBACC         79      /* Can not access a needed shared library */
+#define        ELIBBAD         80      /* Accessing a corrupted shared library */
+#define        ELIBSCN         81      /* .lib section in a.out corrupted */
+#define        ELIBMAX         82      /* Attempting to link in too many shared libraries */
+#define        ELIBEXEC        83      /* Cannot exec a shared library directly */
+#define        EILSEQ          84      /* Illegal byte sequence */
+#define        ERESTART        85      /* Interrupted system call should be restarted */
+#define        ESTRPIPE        86      /* Streams pipe error */
+#define        EUSERS          87      /* Too many users */
+#define        ENOTSOCK        88      /* Socket operation on non-socket */
+#define        EDESTADDRREQ    89      /* Destination address required */
+#define        EMSGSIZE        90      /* Message too long */
+#define        EPROTOTYPE      91      /* Protocol wrong type for socket */
+#define        ENOPROTOOPT     92      /* Protocol not available */
+#define        EPROTONOSUPPORT 93      /* Protocol not supported */
+#define        ESOCKTNOSUPPORT 94      /* Socket type not supported */
+#define        EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
+#define        EPFNOSUPPORT    96      /* Protocol family not supported */
+#define        EAFNOSUPPORT    97      /* Address family not supported by protocol */
+#define        EADDRINUSE      98      /* Address already in use */
+#define        EADDRNOTAVAIL   99      /* Cannot assign requested address */
+#define        ENETDOWN        100     /* Network is down */
+#define        ENETUNREACH     101     /* Network is unreachable */
+#define        ENETRESET       102     /* Network dropped connection because of reset */
+#define        ECONNABORTED    103     /* Software caused connection abort */
+#define        ECONNRESET      104     /* Connection reset by peer */
+#define        ENOBUFS         105     /* No buffer space available */
+#define        EISCONN         106     /* Transport endpoint is already connected */
+#define        ENOTCONN        107     /* Transport endpoint is not connected */
+#define        ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
+#define        ETOOMANYREFS    109     /* Too many references: cannot splice */
+#define        ETIMEDOUT       110     /* Connection timed out */
+#define        ECONNREFUSED    111     /* Connection refused */
+#define        EHOSTDOWN       112     /* Host is down */
+#define        EHOSTUNREACH    113     /* No route to host */
+#define        EALREADY        114     /* Operation already in progress */
+#define        EINPROGRESS     115     /* Operation now in progress */
+#define        ESTALE          116     /* Stale NFS file handle */
+#define        EUCLEAN         117     /* Structure needs cleaning */
+#define        ENOTNAM         118     /* Not a XENIX named type file */
+#define        ENAVAIL         119     /* No XENIX semaphores available */
+#define        EISNAM          120     /* Is a named type file */
+#define        EREMOTEIO       121     /* Remote I/O error */
+#define        EDQUOT          122     /* Quota exceeded */
+
+#define        ENOMEDIUM       123     /* No medium found */
+#define        EMEDIUMTYPE     124     /* Wrong medium type */
+#define        ECANCELED       125     /* Operation Canceled */
+#define        ENOKEY          126     /* Required key not available */
+#define        EKEYEXPIRED     127     /* Key has expired */
+#define        EKEYREVOKED     128     /* Key has been revoked */
+#define        EKEYREJECTED    129     /* Key was rejected by service */
+
+/* for robust mutexes */
+#define        EOWNERDEAD      130     /* Owner died */
+#define        ENOTRECOVERABLE 131     /* State not recoverable */
+
+#endif
diff --git a/embedded/app/usbcan/can/finish.h b/embedded/app/usbcan/can/finish.h
new file mode 100644 (file)
index 0000000..87df046
--- /dev/null
@@ -0,0 +1,13 @@
+/* finish.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+void msgobj_done(struct msgobj_t *obj);
+void canchip_done(struct canchip_t *chip);
+void candevice_done(struct candevice_t *candev);
+void canhardware_done(struct canhardware_t *candev);
diff --git a/embedded/app/usbcan/can/i82527.h b/embedded/app/usbcan/can/i82527.h
new file mode 100644 (file)
index 0000000..1747396
--- /dev/null
@@ -0,0 +1,177 @@
+/* i82527.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+int i82527_enable_configuration(struct canchip_t *chip);
+int i82527_disable_configuration(struct canchip_t *chip);
+int i82527_chip_config(struct canchip_t *chip);
+int i82527_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, 
+                                               int sampl_pt, int flags);
+int i82527_standard_mask(struct canchip_t *chip, unsigned short code, 
+                                                       unsigned short mask);
+int i82527_extended_mask(struct canchip_t *chip, unsigned long code, 
+                                                       unsigned long mask);
+int i82527_message15_mask(struct canchip_t *chip, unsigned long code, 
+                                                       unsigned long mask);
+int i82527_clear_objects(struct canchip_t *chip);
+int i82527_config_irqs(struct canchip_t *chip, short irqs);
+int i82527_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj);
+int i82527_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
+                                                       struct canmsg_t *msg);
+int i82527_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
+                                                       struct canmsg_t *msg);
+int i82527_remote_request(struct canchip_t *chip, struct msgobj_t *obj);
+int i82527_set_btregs(struct canchip_t *chip, unsigned short btr0, 
+                                                       unsigned short btr1);
+int i82527_start_chip(struct canchip_t *chip);
+int i82527_stop_chip(struct canchip_t *chip);
+int i82527_check_tx_stat(struct canchip_t *chip);
+int i82527_irq_handler(int irq, struct canchip_t *chip);
+int i82527_fill_chipspecops(struct canchip_t *chip);
+
+
+#define MSG_OFFSET(object) ((object)*0x10)
+
+#define iCTL 0x00              // Control Register
+#define iSTAT 0x01             // Status Register
+#define iCPU 0x02              // CPU Interface Register
+#define iHSR 0x04              // High Speed Read
+#define iSGM0 0x06             // Standard Global Mask byte 0
+#define iSGM1 0x07
+#define iEGM0 0x08             // Extended Global Mask byte 0
+#define iEGM1 0x09
+#define iEGM2 0x0a
+#define iEGM3 0x0b
+#define i15M0 0x0c             // Message 15 Mask byte 0
+#define i15M1 0x0d
+#define i15M2 0x0e
+#define i15M3 0x0f
+#define iCLK 0x1f              // Clock Out Register
+#define iBUS 0x2f              // Bus Configuration Register
+#define iBT0 0x3f              // Bit Timing Register byte 0
+#define iBT1 0x4f
+#define iIRQ 0x5f              // Interrupt Register
+#define iP1C 0x9f              // Port 1 Register
+#define iP2C 0xaf              // Port 2 Register
+#define iP1I 0xbf              // Port 1 Data In Register
+#define iP2I 0xcf              // Port 2 Data In Register
+#define iP1O 0xdf              // Port 1 Data Out Register
+#define iP2O 0xef              // Port 2 Data Out Register
+#define iSRA 0xff              // Serial Reset Address
+
+#define iMSGCTL0       0x00    /* First Control register */
+#define iMSGCTL1       0x01    /* Second Control register */
+#define iMSGID0                0x02    /* First Byte of Message ID */
+#define iMSGID1                0x03
+#define iMSGID2                0x04
+#define iMSGID3                0x05
+#define iMSGCFG                0x06    /* Message Configuration */
+#define iMSGDAT0       0x07    /* First Data Byte */
+#define iMSGDAT1       0x08
+#define iMSGDAT2       0x09
+#define iMSGDAT3       0x0a
+#define iMSGDAT4       0x0b
+#define iMSGDAT5       0x0c
+#define iMSGDAT6       0x0d
+#define iMSGDAT7       0x0e
+
+/* Control Register (0x00) */
+enum i82527_iCTL {
+       iCTL_INI = 1,           // Initialization
+       iCTL_IE  = 1<<1,        // Interrupt Enable
+       iCTL_SIE = 1<<2,        // Status Interrupt Enable
+       iCTL_EIE = 1<<3,        // Error Interrupt Enable
+       iCTL_CCE = 1<<6         // Change Configuration Enable
+};
+
+/* Status Register (0x01) */
+enum i82527_iSTAT {
+       iSTAT_TXOK = 1<<3,      // Transmit Message Successfully
+       iSTAT_RXOK = 1<<4,      // Receive Message Successfully
+       iSTAT_WAKE = 1<<5,      // Wake Up Status
+       iSTAT_WARN = 1<<6,      // Warning Status
+       iSTAT_BOFF = 1<<7       // Bus Off Status
+};
+
+/* CPU Interface Register (0x02) */
+enum i82527_iCPU {
+       iCPU_CEN = 1,           // Clock Out Enable
+       iCPU_MUX = 1<<2,        // Multiplex
+       iCPU_SLP = 1<<3,        // Sleep
+       iCPU_PWD = 1<<4,        // Power Down Mode
+       iCPU_DMC = 1<<5,        // Divide Memory Clock
+       iCPU_DSC = 1<<6,        // Divide System Clock
+       iCPU_RST = 1<<7         // Hardware Reset Status
+};
+
+/* Clock Out Register (0x1f) */
+enum i82527_iCLK {
+       iCLK_CD0 = 1,           // Clock Divider bit 0
+       iCLK_CD1 = 1<<1,
+       iCLK_CD2 = 1<<2,
+       iCLK_CD3 = 1<<3,
+       iCLK_SL0 = 1<<4,        // Slew Rate bit 0
+       iCLK_SL1 = 1<<5
+};
+
+/* Bus Configuration Register (0x2f) */
+enum i82527_iBUS {
+       iBUS_DR0 = 1,           // Disconnect RX0 Input
+       iBUS_DR1 = 1<<1,        // Disconnect RX1 Input
+       iBUS_DT1 = 1<<3,        // Disconnect TX1 Output
+       iBUS_POL = 1<<5,        // Polarity
+       iBUS_CBY = 1<<6         // Comparator Bypass
+};
+
+#define RESET 1                        // Bit Pair Reset Status
+#define SET 2                  // Bit Pair Set Status
+#define UNCHANGED 3            // Bit Pair Unchanged
+
+/* Message Control Register 0 (Base Address + 0x0) */
+enum i82527_iMSGCTL0 {
+       INTPD_SET = SET,                // Interrupt pending
+       INTPD_RES = RESET,              // No Interrupt pending
+       INTPD_UNC = UNCHANGED,
+       RXIE_SET  = SET<<2,             // Receive Interrupt Enable
+       RXIE_RES  = RESET<<2,           // Receive Interrupt Disable
+       RXIE_UNC  = UNCHANGED<<2,
+       TXIE_SET  = SET<<4,             // Transmit Interrupt Enable
+       TXIE_RES  = RESET<<4,           // Transmit Interrupt Disable
+       TXIE_UNC  = UNCHANGED<<4,
+       MVAL_SET  = SET<<6,             // Message Valid
+       MVAL_RES  = RESET<<6,           // Message Invalid
+       MVAL_UNC  = UNCHANGED<<6
+};
+
+/* Message Control Register 1 (Base Address + 0x01) */
+enum i82527_iMSGCTL1 {
+       NEWD_SET = SET,                 // New Data
+       NEWD_RES = RESET,               // No New Data
+       NEWD_UNC = UNCHANGED,
+       MLST_SET = SET<<2,              // Message Lost
+       MLST_RES = RESET<<2,            // No Message Lost
+       MLST_UNC = UNCHANGED<<2,
+       CPUU_SET = SET<<2,              // CPU Updating
+       CPUU_RES = RESET<<2,            // No CPU Updating
+       CPUU_UNC = UNCHANGED<<2,
+       TXRQ_SET = SET<<4,              // Transmission Request
+       TXRQ_RES = RESET<<4,            // No Transmission Request
+       TXRQ_UNC = UNCHANGED<<4,
+       RMPD_SET = SET<<6,              // Remote Request Pending
+       RMPD_RES = RESET<<6,            // No Remote Request Pending
+       RMPD_UNC = UNCHANGED<<6
+};
+
+/* Message Configuration Register (Base Address + 0x06) */
+enum i82527_iMSGCFG {
+       MCFG_XTD = 1<<2,                // Extended Identifier
+       MCFG_DIR = 1<<3                 // Direction is Transmit
+};
+
+void i82527_seg_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address);
+unsigned i82527_seg_read_reg(const struct canchip_t *chip, unsigned address);
diff --git a/embedded/app/usbcan/can/main.h b/embedded/app/usbcan/can/main.h
new file mode 100644 (file)
index 0000000..23c8ab3
--- /dev/null
@@ -0,0 +1,523 @@
+/* main.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+
+#include <malloc.h>
+
+#include "./can.h"
+#include "./constants.h"
+#include "./ul_listbase.h"
+#include "./can_sysless.h"
+#include "./can_queue.h"
+#include "./errno.h"
+
+#ifdef CAN_DEBUG
+       #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "USBCAN(debug): " fmt,\
+       ##args)
+#else
+       #define DEBUGMSG(fmt,args...)
+#endif
+
+#define CANMSG(fmt,args...) can_printk(KERN_ERR "USBCAN: " fmt,##args)
+
+
+extern can_spinlock_t canuser_manipulation_lock;
+
+/**
+ * struct canhardware_t - structure representing pointers to all CAN boards
+ * @nr_boards: number of present boards
+ * @rtr_queue: RTR - remote transmission request queue (expect some changes there)
+ * @rtr_lock: locking for RTR queue
+ * @candevice: array of pointers to CAN devices/boards
+ */
+struct canhardware_t {
+       int nr_boards;
+       struct rtr_id *rtr_queue;
+       can_spinlock_t rtr_lock;
+       struct candevice_t *candevice[MAX_HW_CARDS];
+};
+
+/**
+ * struct candevice_t - CAN device/board structure
+ * @hwname: text string with board type
+ * @candev_idx: board index in canhardware_t.candevice[]
+ * @io_addr: IO/physical MEM address
+ * @res_addr: optional reset register port
+ * @dev_base_addr: CPU translated IO/virtual MEM address
+ * @flags: board flags: %PROGRAMMABLE_IRQ .. interrupt number
+ *     can be programmed into board
+ * @nr_all_chips: number of chips present on the board
+ * @nr_82527_chips: number of Intel 8257 chips
+ * @nr_sja1000_chips: number of Philips SJA100 chips
+ * @chip: array of pointers to the chip structures
+ * @hwspecops: pointer to board specific operations
+ * @hosthardware_p: pointer to the root hardware structure
+ * @sysdevptr: union reserved for pointer to bus specific
+ *     device structure (case @pcidev is used for PCI devices)
+ *
+ * The structure represent configuration and state of associated board.
+ * The driver infrastructure prepares this structure and calls
+ * board type specific board_register() function. The board support provided
+ * register function fills right function pointers in @hwspecops structure.
+ * Then driver setup calls functions init_hw_data(), init_chip_data(),
+ * init_chip_data(), init_obj_data() and program_irq(). Function init_hw_data()
+ * and init_chip_data() have to specify number and types of connected chips
+ * or objects respectively.
+ * The use of @nr_all_chips is preferred over use of fields @nr_82527_chips
+ * and @nr_sja1000_chips in the board non-specific functions.
+ * The @io_addr and @dev_base_addr is filled from module parameters
+ * to the same value. The request_io function can fix-up @dev_base_addr
+ * field if virtual address is different than bus address.
+ */
+struct candevice_t {
+       char *hwname;                   /* text board type */
+       int candev_idx;                 /* board index in canhardware_t.candevice[] */
+       unsigned long io_addr;          /* IO/physical MEM address */
+       unsigned long res_addr;         /* optional reset register port */
+       unsigned long dev_base_addr;    /* CPU translated IO/virtual MEM address */
+       unsigned int flags;
+       int nr_all_chips;
+       int nr_82527_chips;
+       int nr_sja1000_chips;
+       can_spinlock_t device_lock;
+       struct canchip_t *chip[MAX_HW_CHIPS];
+
+       struct hwspecops_t *hwspecops;
+
+       struct canhardware_t *hosthardware_p;
+
+       union {
+               void *anydev;
+           #ifdef CAN_ENABLE_PCI_SUPPORT
+               struct pci_dev *pcidev;
+           #endif /*CAN_ENABLE_PCI_SUPPORT*/
+       } sysdevptr;
+
+};
+
+/**
+ * struct canchip_t - CAN chip state and type information
+ * @chip_type: text string describing chip type
+ * @chip_idx: index of the chip in candevice_t.chip[] array
+ * @chip_irq: chip interrupt number if any
+ * @chip_base_addr: chip base address in the CPU IO or virtual memory space
+ * @flags: chip flags: %CHIP_CONFIGURED .. chip is configured,
+ *     %CHIP_SEGMENTED .. access to the chip is segmented (mainly for i82527 chips)
+ * @clock: chip base clock frequency in Hz
+ * @baudrate: selected chip baudrate in Hz
+ * @write_register: write chip register function copy
+ * @read_register: read chip register function copy
+ * @chip_data: pointer for optional chip specific data extension
+ * @sja_cdr_reg: SJA specific register -
+ *     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
+ * @sja_ocr_reg: SJA specific register -
+ *     hold 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.
+ * @int_cpu_reg: Intel specific register -
+ *     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.
+ * @int_clk_reg: Intel specific register -
+ *     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.
+ * @int_bus_reg: Intel specific register -
+ *     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.
+ * @msgobj: array of pointers to individual communication objects
+ * @chipspecops: pointer to the set of chip specific object filled by init_chip_data() function
+ * @hostdevice: pointer to chip hosting board
+ * @max_objects: maximal number of communication objects connected to this chip
+ * @chip_lock: reserved for synchronization of the chip supporting routines
+ *     (not used in the current driver version)
+ * @worker_thread: chip worker thread ID (RT-Linux specific field)
+ * @pend_flags: holds information about pending interrupt and tx_wake() operations
+ *     (RT-Linux specific field). Masks values:
+ *     %MSGOBJ_TX_REQUEST .. some of the message objects requires tx_wake() call,
+ *     %MSGOBJ_IRQ_REQUEST .. chip interrupt processing required
+ *     %MSGOBJ_WORKER_WAKE .. marks, that worker thread should be waked
+ *             for some of above reasons
+ *
+ * The fields @write_register and @read_register are copied from
+ * corresponding fields from @hwspecops structure
+ * (chip->hostdevice->hwspecops->write_register and
+ * chip->hostdevice->hwspecops->read_register)
+ * to speedup can_write_reg() and can_read_reg() functions.
+ */
+struct canchip_t {
+       char *chip_type;
+       int chip_idx;   /* chip index in candevice_t.chip[] */
+       int chip_irq;
+       unsigned long chip_base_addr;
+       unsigned int flags;
+       long clock; /* Chip clock in Hz */
+       long baudrate;
+
+       void (*write_register)(unsigned data,unsigned long address);
+       unsigned (*read_register)(unsigned long address);
+
+       void *chip_data;
+
+       unsigned short sja_cdr_reg; /* sja1000 only! */
+       unsigned short sja_ocr_reg; /* sja1000 only! */
+       unsigned short int_cpu_reg; /* intel 82527 only! */
+       unsigned short int_clk_reg; /* intel 82527 only! */
+       unsigned short int_bus_reg; /* intel 82527 only! */
+
+       struct msgobj_t *msgobj[MAX_MSGOBJS];
+
+       struct chipspecops_t *chipspecops;
+
+       struct candevice_t *hostdevice;
+
+       int max_objects;        /* 1 for sja1000, 15 for i82527 */
+
+       can_spinlock_t chip_lock;
+
+    #ifdef CAN_WITH_RTL
+       pthread_t worker_thread;
+       unsigned long pend_flags;
+    #endif /*CAN_WITH_RTL*/
+};
+
+/**
+ * struct msgobj_t - structure holding communication object state
+ * @obj_base_addr:
+ * @minor: associated device minor number
+ * @object: object number in canchip_t structure +1
+ * @flags: message object flags
+ * @ret: field holding status of the last Tx operation
+ * @qends: pointer to message object corresponding ends structure
+ * @tx_qedge: edge corresponding to transmitted message
+ * @tx_slot: slot holding transmitted message, slot is taken from
+ *     canque_test_outslot() call and is freed by canque_free_outslot()
+ *     or rescheduled canque_again_outslot()
+ * @tx_retry_cnt: transmission attempt counter
+ * @tx_timeout: can be used by chip driver to check for the transmission timeout
+ * @rx_msg: temporary storage to hold received messages before
+ *     calling to canque_filter_msg2edges()
+ * @hostchip: pointer to the &canchip_t structure this object belongs to
+ * @obj_used: counter of users (associated file structures for Linux
+ *     userspace clients) of this object
+ * @obj_users: list of user structures of type &canuser_t.
+ * @obj_flags: message object specific flags. Masks values:
+ *     %MSGOBJ_TX_REQUEST .. the message object requests TX activation
+ *     %MSGOBJ_TX_LOCK .. some IRQ routine or callback on some CPU
+ *             is running inside TX activation processing code
+ * @rx_preconfig_id: place to store RX message identifier for some chip types
+ *              that reuse same object for TX
+ */
+struct msgobj_t {
+       unsigned long obj_base_addr;
+       unsigned int minor;     /* associated device minor number  */
+       unsigned int object;    /* object number in canchip_t +1 for debug printk */
+       unsigned long obj_flags;
+       int ret;
+
+       struct canque_ends_t *qends;
+
+       struct canque_edge_t *tx_qedge;
+       struct canque_slot_t *tx_slot;
+       int tx_retry_cnt;
+       struct timer_list tx_timeout;
+
+       struct canmsg_t rx_msg;
+
+       struct canchip_t *hostchip;
+
+       unsigned long rx_preconfig_id;
+
+       atomic_t obj_used;
+       struct list_head obj_users;
+};
+
+#define CAN_USER_MAGIC 0x05402033
+
+/**
+ * struct canuser_t - structure holding CAN user/client state
+ * @flags: used to distinguish Linux/RT-Linux type
+ * @peers: for connection into list of object users
+ * @qends: pointer to the ends structure corresponding for this user
+ * @msgobj: communication object the user is connected to
+ * @rx_edge0: default receive queue for filter IOCTL
+ * @userinfo: stores user context specific information.
+ *     The field @fileinfo.file holds pointer to open device file state structure
+ *     for the Linux user-space client applications
+ * @magic: magic number to check consistency when pointer is retrieved
+ *     from file private field
+ */
+struct canuser_t {
+       unsigned long flags;
+       struct list_head peers;
+       struct canque_ends_t *qends;
+       struct msgobj_t *msgobj;
+       struct canque_edge_t *rx_edge0; /* simplifies IOCTL */
+        union {
+               struct {
+                       struct file *file;  /* back ptr to file */
+               } fileinfo;
+           #ifdef CAN_WITH_RTL
+               struct {
+                       struct rtl_file *file;
+               } rtlinfo;
+           #endif /*CAN_WITH_RTL*/
+       } userinfo;
+       int magic;
+};
+
+/**
+ * struct hwspecops_t - hardware/board specific operations
+ * @request_io: reserve io or memory range for can board
+ * @release_io: free reserved io memory range
+ * @reset: hardware reset routine
+ * @init_hw_data: called to initialize &candevice_t structure, mainly
+ *     @res_add, @nr_all_chips, @nr_82527_chips, @nr_sja1000_chips
+ *     and @flags fields
+ * @init_chip_data: called initialize each &canchip_t structure, mainly
+ *     @chip_type, @chip_base_addr, @clock and chip specific registers.
+ *     It is responsible to setup &canchip_t->@chipspecops functions
+ *     for non-standard chip types (type other than "i82527", "sja1000" or "sja1000p")
+ * @init_obj_data: called initialize each &msgobj_t structure,
+ *     mainly @obj_base_addr field.
+ * @program_irq: program interrupt generation hardware of the board
+ *     if flag %PROGRAMMABLE_IRQ is present for specified device/board
+ * @write_register: low level write register routine
+ * @read_register: low level read register routine
+ */
+struct hwspecops_t {
+       int (*request_io)(struct candevice_t *candev);
+       int (*release_io)(struct candevice_t *candev);
+       int (*reset)(struct candevice_t *candev);
+       int (*init_hw_data)(struct candevice_t *candev);
+       int (*init_chip_data)(struct candevice_t *candev, int chipnr);
+       int (*init_obj_data)(struct canchip_t *chip, int objnr);
+       int (*program_irq)(struct candevice_t *candev);
+       void (*write_register)(unsigned data,unsigned long address);
+       unsigned (*read_register)(unsigned long address);
+};
+
+/**
+ * struct chipspecops_t - can controller chip specific operations
+ * @chip_config: CAN chip configuration
+ * @baud_rate: set communication parameters
+ * @standard_mask: setup of mask for message filtering
+ * @extended_mask: setup of extended mask for message filtering
+ * @message15_mask: set mask of i82527 message object 15
+ * @clear_objects: clears state of all message object residing in chip
+ * @config_irqs: tunes chip hardware interrupt delivery
+ * @pre_read_config: prepares message object for message reception
+ * @pre_write_config: prepares message object for message transmission
+ * @send_msg: initiate message transmission
+ * @remote_request: configures message object and asks for RTR message
+ * @check_tx_stat: checks state of transmission engine
+ * @wakeup_tx: wakeup TX processing
+ * @filtch_rq: optional routine for propagation of outgoing edges filters to HW
+ * @enable_configuration: enable chip configuration mode
+ * @disable_configuration: disable chip configuration mode
+ * @set_btregs: configures bitrate registers
+ * @attach_to_chip: attaches to the chip, setups registers and possibly state informations
+ * @release_chip: called before chip structure removal if %CHIP_ATTACHED is set
+ * @start_chip: starts chip message processing
+ * @stop_chip: stops chip message processing
+ * @irq_handler: interrupt service routine
+ * @irq_accept: optional fast irq accept routine responsible for blocking further interrupts
+ */
+struct chipspecops_t {
+       int (*chip_config)(struct canchip_t *chip);
+       int (*baud_rate)(struct canchip_t *chip, int rate, int clock, int sjw,
+                                               int sampl_pt, int flags);
+       int (*standard_mask)(struct canchip_t *chip, unsigned short code,
+                                                       unsigned short mask);
+       int (*extended_mask)(struct canchip_t *chip, unsigned long code,
+                                                       unsigned long mask);
+       int (*message15_mask)(struct canchip_t *chip, unsigned long code,
+                                                       unsigned long mask);
+       int (*clear_objects)(struct canchip_t *chip);
+       int (*config_irqs)(struct canchip_t *chip, short irqs);
+       int (*pre_read_config)(struct canchip_t *chip, struct msgobj_t *obj);
+       int (*pre_write_config)(struct canchip_t *chip, struct msgobj_t *obj,
+                                                       struct canmsg_t *msg);
+       int (*send_msg)(struct canchip_t *chip, struct msgobj_t *obj,
+                                                       struct canmsg_t *msg);
+       int (*remote_request)(struct canchip_t *chip, struct msgobj_t *obj);
+       int (*check_tx_stat)(struct canchip_t *chip);
+       int (*wakeup_tx)(struct canchip_t *chip, struct msgobj_t *obj);
+       int (*filtch_rq)(struct canchip_t *chip, struct msgobj_t *obj);
+       int (*enable_configuration)(struct canchip_t *chip);
+       int (*disable_configuration)(struct canchip_t *chip);
+       int (*set_btregs)(struct canchip_t *chip, unsigned short btr0,
+                                                       unsigned short btr1);
+       int (*attach_to_chip)(struct canchip_t *chip);
+       int (*release_chip)(struct canchip_t *chip);
+       int (*start_chip)(struct canchip_t *chip);
+       int (*stop_chip)(struct canchip_t *chip);
+       int (*irq_handler)(int irq, struct canchip_t *chip);
+       int (*irq_accept)(int irq, struct canchip_t *chip);
+};
+
+struct mem_addr {
+       void *address;
+       struct mem_addr *next;
+       size_t size;
+};
+
+/* Structure for the RTR queue */
+struct rtr_id {
+       unsigned long id;
+       struct canmsg_t *rtr_message;
+       wait_queue_head_t rtr_wq;
+       struct rtr_id *next;
+};
+
+extern int major;
+extern int minor[MAX_TOT_CHIPS];
+extern int extended;
+extern int baudrate[MAX_TOT_CHIPS];
+extern char *hw[MAX_HW_CARDS];
+extern int irq[MAX_IRQ];
+extern unsigned long io[MAX_HW_CARDS];
+extern int processlocal;
+
+extern struct canhardware_t *hardware_p;
+//extern struct canchip_t *chips_p[MAX_TOT_CHIPS];
+struct canchip_t *chips_p[MAX_TOT_CHIPS];
+extern struct msgobj_t *objects_p[MAX_TOT_MSGOBJS];
+
+extern struct mem_addr *mem_head;
+
+
+#if defined(CONFIG_OC_LINCAN_PORTIO_ONLY)
+extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address)
+{
+       outb(data, chip->chip_base_addr+address);
+}
+extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address)
+{
+       return inb(chip->chip_base_addr+address);
+}
+extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
+                               unsigned char data, unsigned address)
+{
+       outb(data, obj->obj_base_addr+address);
+}
+extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
+                               unsigned address)
+{
+       return inb(obj->obj_base_addr+address);
+}
+
+#elif defined(CONFIG_OC_LINCAN_MEMIO_ONLY)
+extern inline void can_write_reg(const struct canchip_t *chip, unsigned char data, unsigned address)
+{
+       writeb(data, chip->chip_base_addr+address);
+}
+extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address)
+{
+       return readb(chip->chip_base_addr+address);
+}
+extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
+                               unsigned char data, unsigned address)
+{
+       writeb(data, obj->obj_base_addr+address);
+}
+extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
+                               unsigned address)
+{
+       return readb(obj->obj_base_addr+address);
+}
+
+#else /*CONFIG_OC_LINCAN_DYNAMICIO*/
+#ifndef CONFIG_OC_LINCAN_DYNAMICIO
+#define CONFIG_OC_LINCAN_DYNAMICIO
+#endif
+
+/* 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(const struct canchip_t *chip, unsigned char data, unsigned address)
+{
+       unsigned long address_to_write;
+       address_to_write = chip->chip_base_addr+address;
+       chip->write_register(data, address_to_write);
+}
+
+extern inline unsigned can_read_reg(const struct canchip_t *chip, unsigned address)
+{
+       unsigned long address_to_read;
+       address_to_read = chip->chip_base_addr+address;
+       return chip->read_register(address_to_read);
+}
+
+extern inline void canobj_write_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
+                               unsigned char data, unsigned address)
+{
+       unsigned long address_to_write;
+       address_to_write = obj->obj_base_addr+address;
+       chip->write_register(data, address_to_write);
+}
+
+extern inline unsigned canobj_read_reg(const struct canchip_t *chip, const struct msgobj_t *obj,
+                               unsigned address)
+{
+       unsigned long address_to_read;
+       address_to_read = obj->obj_base_addr+address;
+       return chip->read_register(address_to_read);
+}
+
+#endif /*CONFIG_OC_LINCAN_DYNAMICIO*/
+
+int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base);
+int can_request_io_region(unsigned long start, unsigned long n, const char *name);
+void can_release_io_region(unsigned long start, unsigned long n);
+int can_request_mem_region(unsigned long start, unsigned long n, const char *name);
+void can_release_mem_region(unsigned long start, unsigned long n);
+
+struct boardtype_t {
+       const char *boardtype;
+       int (*board_register)(struct hwspecops_t *hwspecops);
+       int irqnum;
+};
+
+const struct boardtype_t* boardtype_find(const char *str);
+
+int can_check_dev_taken(void *anydev);
+
+#if defined(can_gettimeofday) && defined(CAN_MSG_VERSION_2) && 1
+static inline
+void can_filltimestamp(canmsg_tstamp_t *ptimestamp)
+{
+       can_gettimeofday(ptimestamp);
+}
+#else /* No timestamp support, set field to zero */
+static inline
+void can_filltimestamp(canmsg_tstamp_t *ptimestamp)
+{
+    #ifdef CAN_MSG_VERSION_2
+       ptimestamp->tv_sec = 0;
+       ptimestamp->tv_usec = 0;
+    #else /* CAN_MSG_VERSION_2 */
+       *ptimestamp = 0;
+    #endif /* CAN_MSG_VERSION_2 */
+
+}
+#endif /* End of timestamp source selection */
+
+#ifdef CAN_WITH_RTL
+extern int can_rtl_priority;
+#endif /*CAN_WITH_RTL*/
+
+#endif /* MAIN_H */
+
diff --git a/embedded/app/usbcan/can/modparms.h b/embedded/app/usbcan/can/modparms.h
new file mode 100644 (file)
index 0000000..6691931
--- /dev/null
@@ -0,0 +1,10 @@
+/* mod_parms.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+int parse_mod_parms(void);
diff --git a/embedded/app/usbcan/can/setup.h b/embedded/app/usbcan/can/setup.h
new file mode 100644 (file)
index 0000000..d35a8b1
--- /dev/null
@@ -0,0 +1,16 @@
+/* setup.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+int init_hw_struct(void);
+int list_hw(void);
+void *can_checked_malloc(size_t size);
+int can_checked_free(void *address_p);
+int can_del_mem_list(void);
+int can_chip_setup_irq(struct canchip_t *chip);
+void can_chip_free_irq(struct canchip_t *chip);
diff --git a/embedded/app/usbcan/can/sja1000p.h b/embedded/app/usbcan/can/sja1000p.h
new file mode 100644 (file)
index 0000000..fe81a9c
--- /dev/null
@@ -0,0 +1,205 @@
+/* sja1000p.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Added by T.Motylewski@bfad.de
+ * See app. note an97076.pdf from Philips Semiconductors
+ * and SJA1000 data sheet
+ * PELICAN mode
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#ifndef SJA1000P_H
+#define SJA1000P_H
+
+int sja1000p_chip_config(struct canchip_t *chip);
+int sja1000p_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask);
+int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
+               int sampl_pt, int flags);
+int sja1000p_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj);
+int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
+               struct canmsg_t *msg);
+int sja1000p_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
+               struct canmsg_t *msg);
+int sja1000p_fill_chipspecops(struct canchip_t *chip);
+int sja1000p_irq_handler(int irq, struct canchip_t *chip);
+
+
+/* PeliCAN mode */
+enum SJA1000_PeliCAN_regs {
+       SJAMOD  = 0x00,
+/// Command register
+       SJACMR  = 0x01,
+/// Status register
+       SJASR   = 0x02,
+/// Interrupt register
+       SJAIR   = 0x03,
+/// Interrupt Enable
+       SJAIER  = 0x04,
+/// Bus Timing register 0
+       SJABTR0 = 0x06,
+/// Bus Timing register 1
+       SJABTR1 = 0x07,
+/// Output Control register
+       SJAOCR  = 0x08,
+/// Arbitration Lost Capture
+       SJAALC  = 0x0b,
+/// Error Code Capture
+       SJAECC  = 0x0c,
+/// Error Warning Limit
+       SJAEWLR = 0x0d,
+/// RX Error Counter
+       SJARXERR = 0x0e,
+/// TX Error Counter
+       SJATXERR0 = 0x0e,
+       SJATXERR1 = 0x0f,
+/// Rx Message Counter (number of msgs. in RX FIFO
+       SJARMC  = 0x1d,
+/// Rx Buffer Start Addr. (address of current MSG)
+       SJARBSA = 0x1e,
+/// Transmit Buffer (write) Receive Buffer (read) Frame Information
+       SJAFRM = 0x10,
+/// ID bytes (11 bits in 0 and 1 or 16 bits in 0,1 and 13 bits in 2,3 (extended))
+       SJAID0 = 0x11, SJAID1 = 0x12,
+/// ID cont. for extended frames
+       SJAID2 = 0x13, SJAID3 = 0x14,
+/// Data start standard frame
+       SJADATS = 0x13,
+/// Data start extended frame
+       SJADATE = 0x15,
+/// Acceptance Code (4 bytes) in RESET mode
+       SJAACR0 = 0x10,
+/// Acceptance Mask (4 bytes) in RESET mode
+       SJAAMR0 = 0x14,
+/// 4 bytes
+       SJA_PeliCAN_AC_LEN = 4,
+/// Clock Divider
+       SJACDR = 0x1f
+};
+
+/** Mode Register 0x00 */
+enum sja1000_PeliCAN_MOD {
+       sjaMOD_SM = 1<<4,  // Sleep Mode (writable only in OPERATING mode)
+       sjaMOD_AFM= 1<<3,  // Acceptance Filter Mode (writable only in RESET)
+       sjaMOD_STM= 1<<2,  // Self Test Mode (writable only in RESET)
+       sjaMOD_LOM= 1<<1,  // Listen Only Mode (writable only in RESET)
+       sjaMOD_RM = 1      // Reset Mode
+};
+
+/** Command Register 0x01 */
+enum sja1000_PeliCAN_CMR {
+       sjaCMR_SRR= 1<<4,  // Self Reception Request (GoToSleep in BASIC mode)
+       sjaCMR_CDO= 1<<3,  // Clear Data Overrun
+       sjaCMR_RRB= 1<<2,  // Release Receive Buffer
+       sjaCMR_AT = 1<<1,  // Abort Transmission
+       sjaCMR_TR = 1 };   // Transmission Request
+
+/** Status Register 0x02 */
+enum sja1000_SR {
+       sjaSR_BS  = 1<<7,  // Bus Status
+       sjaSR_ES  = 1<<6,  // Error Status
+       sjaSR_TS  = 1<<5,  // Transmit Status
+       sjaSR_RS  = 1<<4,  // Receive Status
+       sjaSR_TCS = 1<<3,  // Transmission Complete Status
+       sjaSR_TBS = 1<<2,  // Transmit Buffer Status
+       sjaSR_DOS = 1<<1,  // Data Overrun Status
+       sjaSR_RBS = 1 };   // Receive Buffer Status
+
+/** Interrupt Enable Register 0x04 */
+enum sja1000_PeliCAN_IER {
+       sjaIER_BEIE= 1<<7, // Bus Error Interrupt Enable
+       sjaIER_ALIE= 1<<6, // Arbitration Lost Interrupt Enable
+       sjaIER_EPIE= 1<<5, // Error Passive Interrupt Enable
+       sjaIER_WUIE= 1<<4, // Wake-Up Interrupt Enable
+       sjaIER_DOIE= 1<<3, // Data Overrun Interrupt Enable
+       sjaIER_EIE = 1<<2, // Error Warning Interrupt Enable
+       sjaIER_TIE = 1<<1, // Transmit Interrupt Enable
+       sjaIER_RIE = 1,    // Receive Interrupt Enable
+       sjaENABLE_INTERRUPTS = sjaIER_BEIE|sjaIER_EPIE|sjaIER_DOIE|sjaIER_EIE|sjaIER_TIE|sjaIER_RIE,
+       sjaDISABLE_INTERRUPTS = 0
+// WARNING: the chip automatically enters RESET (bus off) mode when
+       // error counter > 255
+};
+
+/** Arbitration Lost Capture Register 0x0b.
+ * Counting starts from 0 (bit1 of ID). Bits 5-7 reserved*/
+enum sja1000_PeliCAN_ALC {
+       sjaALC_SRTR = 0x0b,// Arbitration lost in bit SRTR
+       sjaALC_IDE  = 0x1c, // Arbitration lost in bit IDE
+       sjaALC_RTR  = 0x1f, // Arbitration lost in RTR
+};
+
+/** Error Code Capture Register 0x0c*/
+enum sja1000_PeliCAN_ECC {
+       sjaECC_ERCC1 = 1<<7,
+       sjaECC_ERCC0 = 1<<6,
+       sjaECC_BIT   = 0,
+       sjaECC_FORM  = sjaECC_ERCC0,
+       sjaECC_STUFF = sjaECC_ERCC1,
+       sjaECC_OTHER = sjaECC_ERCC0 | sjaECC_ERCC1,
+       sjaECC_DIR   = 1<<5,    // 1 == RX, 0 == TX
+       sjaECC_SEG_M = (1<<5) -1 // Segment mask, see page 37 of SJA1000 Data Sheet
+};
+
+/** Frame format information 0x10 */
+enum sja1000_PeliCAN_FRM {
+       sjaFRM_FF = 1<<7, // Frame Format 1 == extended, 0 == standard
+       sjaFRM_RTR = 1<<6, // Remote request
+       sjaFRM_DLC_M = (1<<4)-1 // Length Mask
+};
+
+
+/** Interrupt (status) Register 0x03 */
+enum sja1000_PeliCAN_IR {
+       sjaIR_BEI = 1<<7,  // Bus Error Interrupt
+       sjaIR_ALI = 1<<6,  // Arbitration Lost Interrupt
+       sjaIR_EPI = 1<<5,  // Error Passive Interrupt (entered error passive state or error active state)
+       sjaIR_WUI = 1<<4,  // Wake-Up Interrupt
+       sjaIR_DOI = 1<<3,  // Data Overrun Interrupt
+       sjaIR_EI  = 1<<2,  // Error Interrupt
+       sjaIR_TI  = 1<<1,  // Transmit Interrupt
+       sjaIR_RI  = 1      // Receive Interrupt
+};
+
+/** Bus Timing 1 Register 0x07 */
+enum sja1000_BTR1 {
+       sjaMAX_TSEG1 = 15,
+       sjaMAX_TSEG2 = 7
+};
+
+/** Output Control Register 0x08 */
+enum sja1000_OCR {
+       sjaOCR_MODE_BIPHASE = 0,
+       sjaOCR_MODE_TEST = 1,
+       sjaOCR_MODE_NORMAL = 2,
+       sjaOCR_MODE_CLOCK = 3,
+/// TX0 push-pull not inverted
+       sjaOCR_TX0_LH = 0x18,
+/// TX1 floating (off)
+       sjaOCR_TX1_ZZ = 0
+};
+
+/** Clock Divider register 0x1f */
+enum sja1000_CDR {
+       sjaCDR_PELICAN = 1<<7,
+/// bypass input comparator
+       sjaCDR_CBP = 1<<6,
+/// switch TX1 to generate RX INT
+       sjaCDR_RXINPEN = 1<<5,
+       sjaCDR_CLK_OFF = 1<<3,
+/// f_out = f_osc/(2*(CDR[2:0]+1)) or f_osc if CDR[2:0]==7
+       sjaCDR_CLKOUT_DIV1 = 7,
+       sjaCDR_CLKOUT_DIV2 = 0,
+       sjaCDR_CLKOUT_DIV4 = 1,
+       sjaCDR_CLKOUT_DIV6 = 2,
+       sjaCDR_CLKOUT_DIV8 = 3,
+       sjaCDR_CLKOUT_DIV10 = 4,
+       sjaCDR_CLKOUT_DIV12 = 5,
+       sjaCDR_CLKOUT_DIV14 = 6,
+       sjaCDR_CLKOUT_MASK = 7
+};
+
+/** flags for sja1000_baud_rate */
+#define BTR1_SAM (1<<1)
+
+#endif /* SJA1000P_H */
diff --git a/embedded/app/usbcan/can/ul_listbase.h b/embedded/app/usbcan/can/ul_listbase.h
new file mode 100644 (file)
index 0000000..2d4fece
--- /dev/null
@@ -0,0 +1,287 @@
+#ifndef _UL_LISTBASE_H
+#define _UL_LISTBASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __KERNEL__
+
+#define LIST_POISON1  ((void *) 0)
+#define LIST_POISON2  ((void *) 0)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = LIST_POISON1;
+       entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry); 
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+                                 struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+       return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+                                struct list_head *head)
+{
+       struct list_head *first = list->next;
+       struct list_head *last = list->prev;
+       struct list_head *where = head->next;
+
+       first->prev = head;
+       head->next = first;
+
+       last->next = where;
+       where->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+       if (!list_empty(list))
+               __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+                                   struct list_head *head)
+{
+       if (!list_empty(list)) {
+               __list_splice(list, head);
+               INIT_LIST_HEAD(list);
+       }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+               pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each     -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev  -       iterate over a list backwards
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+       for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+               pos = pos->prev, prefetch(pos->prev))
+               
+/**
+ * list_for_each_safe  -       iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry -       iterate over list of given type
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_entry((head)->next, typeof(*pos), member),      \
+                    prefetch(pos->member.next);                        \
+            &pos->member != (head);                                    \
+            pos = list_entry(pos->member.next, typeof(*pos), member),  \
+                    prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)                 \
+       for (pos = list_entry((head)->prev, typeof(*pos), member),      \
+                    prefetch(pos->member.prev);                        \
+            &pos->member != (head);                                    \
+            pos = list_entry(pos->member.prev, typeof(*pos), member),  \
+                    prefetch(pos->member.prev))
+
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_entry((head)->next, typeof(*pos), member),      \
+               n = list_entry(pos->member.next, typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#else /*__KERNEL__*/
+
+#include <linux/list.h>
+
+#endif /*__KERNEL__*/
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* _UL_LISTBASE_H */
diff --git a/embedded/app/usbcan/can/ul_usb1.h b/embedded/app/usbcan/can/ul_usb1.h
new file mode 100644 (file)
index 0000000..385f4e3
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef UL_USB1_H
+#define UL_USB1_H
+
+/* ul_usb1.h
+ * Header file for the Linux CAN-bus driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+struct ul_usb1_chip_data
+{
+       int flags;
+};
+
+#define UL_USB1_CHIP_MASK_SET (1<<0)
+#define UL_USB1_CHIP_BAUD_SET (1<<1)
+
+int ul_usb1_init(void);
+void ul_usb1_exit(void);
+
+extern int ul_usb1_register(struct hwspecops_t *hwspecops);
+
+#endif /* UL_USB1_H */
diff --git a/embedded/app/usbcan/can_quesysless.c b/embedded/app/usbcan/can_quesysless.c
new file mode 100644 (file)
index 0000000..f11f90d
--- /dev/null
@@ -0,0 +1,518 @@
+/* can_quesysless.c - CAN message queues functions for the Linux kernel
+ * Linux CAN-bus device driver.
+ * New CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysdep.h"
+#include "./can/can_queue.h"
+
+// #define CAN_DEBUG
+
+extern atomic_t edge_num_cnt;
+
+#ifdef CAN_DEBUG
+       #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_quesysless (debug): " fmt,\
+       ##args)
+
+#else
+       #define DEBUGQUE(fmt,args...)
+#endif
+
+#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_quesysless: " fmt,\
+       ##args)
+
+
+/*
+ * Modifies Tx message processing
+ *  0 .. local message processing disabled
+ *  1 .. local messages disabled by default but can be enabled by canque_set_filt
+ *  2 .. local messages enabled by default, can be disabled by canque_set_filt
+ */
+extern int processlocal;
+
+void canque_dead_func(unsigned long data);
+
+/* Support for dead ends structures left after client close */
+can_spinlock_t canque_dead_func_lock;
+LIST_HEAD(canque_dead_ends);
+/* retrieved by list_entry(canque_dead_ends.next,struct canque_ends_t,dead_peers) */
+LIST_HEAD(canque_dead_edges);
+/* retrieved by list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers) */
+// DECLARE_TASKLET(canque_dead_tl, canque_dead_func, 0);
+/* activated by tasklet_schedule(&canque_dead_tl) */
+
+
+static inline
+struct canque_edge_t *canque_dead_edges_cut_first(void)
+{
+       can_spin_irqflags_t flags;
+       struct canque_edge_t *edge;
+       can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+       if(list_empty(&canque_dead_edges))
+               edge=NULL;
+       else{
+               edge=list_entry(canque_dead_edges.next,struct canque_edge_t,inpeers);
+               list_del(&edge->inpeers);
+       }
+       can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+       return edge;
+}
+
+void canque_dead_func(unsigned long data)
+{
+       can_spin_irqflags_t flags;
+       struct canque_edge_t *qedge;
+       struct canque_ends_t *qends;
+       struct list_head *entry;
+
+       while((qedge=canque_dead_edges_cut_first())){
+               DEBUGQUE("edge %d disposed\n",qedge->edge_num);
+           #ifdef CAN_WITH_RTL
+               if(canque_fifo_test_fl(&qedge->fifo,RTL_MEM)){
+                       canque_dispose_edge_rtl(qedge);
+                       continue;
+               }
+           #endif /*CAN_WITH_RTL*/
+               canque_fifo_done_kern(&qedge->fifo);
+               free(qedge);
+       }
+
+       can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+       entry=canque_dead_ends.next;
+       while(entry!=&canque_dead_ends){
+               qends=list_entry(entry,struct canque_ends_t,dead_peers);
+               entry=entry->next;
+               if(!list_empty(&qends->inlist))
+                       continue;
+               if(!list_empty(&qends->outlist))
+                       continue;
+               can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+               list_del(&qends->dead_peers);
+               can_spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+               DEBUGQUE("ends structure disposed\n");
+           #ifdef CAN_WITH_RTL
+               if(qends->ends_flags&CAN_ENDSF_MEM_RTL){
+                       canque_ends_free_rtl(qends);
+                       continue;
+               }
+           #endif /*CAN_WITH_RTL*/
+               free(qends);
+       }
+       can_spin_unlock_irqrestore(&canque_dead_func_lock,flags);
+}
+
+// static inline void canque_dead_tasklet_schedule(void)
+// {
+//     #ifdef CAN_WITH_RTL
+//     if(!rtl_rt_system_is_idle()){
+//             set_bit(CAN_RTL2LIN_PEND_DEAD_b,&canqueue_rtl2lin_pend);
+//             rtl_global_pend_irq (canqueue_rtl_irq);
+//             return;
+//     }
+//     #endif /*CAN_WITH_RTL*/
+//
+//     tasklet_schedule(&canque_dead_tl);
+// }
+
+
+void canque_edge_do_dead(struct canque_edge_t *edge)
+{
+       can_spin_irqflags_t flags;
+
+       canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+    #ifdef CAN_WITH_RTL
+       /* The problem of the above call is, that in RT-Linux to Linux notify
+          case is edge scheduled for delayed notify delivery, this needs
+          to be reflected there */
+       if(atomic_read(&edge->edge_used)>0){
+               can_spin_lock_irqsave(&edge->inends->ends_lock, flags);
+               can_spin_lock(&edge->outends->ends_lock);
+               if(atomic_read(&edge->edge_used)>0){
+                       /* left edge to live for a while, banshee comes again in a while */
+                       canque_fifo_clear_fl(&edge->fifo,DEAD);
+                       can_spin_unlock(&edge->outends->ends_lock);
+                       can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags);
+                       can_printk(KERN_ERR "can_quertl (debug): canque_edge_do_dead postponed\n");
+                       return;
+               }
+               can_spin_unlock(&edge->outends->ends_lock);
+               can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags);
+       }
+    #endif /*CAN_WITH_RTL*/
+
+       if(canqueue_disconnect_edge(edge)<0){
+               ERRMSGQUE("canque_edge_do_dead: canqueue_disconnect_edge failed !!!\n");
+               return;
+       }
+
+       can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+       list_add(&edge->inpeers,&canque_dead_edges);
+       can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+//     canque_dead_tasklet_schedule();
+       canque_dead_func(0);
+}
+
+
+
+/*if(qends->ends_flags & CAN_ENDSF_DEAD){
+       can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+       list_del(&qends->dead_peers);
+       list_add(&qends->dead_peers,&canque_dead_ends);
+       can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+       tasklet_schedule(&canque_dead_tl);
+}*/
+
+
+/**
+ * canqueue_notify_kern - notification callback handler for Linux userspace clients
+ * @qends: pointer to the callback side ends structure
+ * @qedge: edge which invoked notification
+ * @what: notification type
+ *
+ * The notification event is handled directly by call of this function except case,
+ * when called from RT-Linux context in mixed mode Linux/RT-Linux compilation.
+ * It is not possible to directly call Linux kernel synchronization primitives
+ * in such case. The notification request is postponed and signaled by @pending_inops flags
+ * by call canqueue_rtl2lin_check_and_pend() function.
+ * The edge reference count is increased until until all pending notifications are processed.
+ */
+void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
+{
+       DEBUGQUE("canqueue_notify_kern for edge %d, use %d and event %d\n",
+                       qedge->edge_num,(int)atomic_read(&qedge->edge_used),what);
+
+       /* delay event delivery for RT-Linux -> kernel notifications */
+       if(canqueue_rtl2lin_check_and_pend(qends,qedge,what)){
+               DEBUGQUE("canqueue_notify_kern postponed\n");
+               return;
+       }
+
+       switch(what){
+               case CANQUEUE_NOTIFY_EMPTY:
+//                     wake_up(&qends->endinfo.fileinfo.emptyq);
+                       if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
+                               canque_edge_decref(qedge);
+                       break;
+               case CANQUEUE_NOTIFY_SPACE:
+//                     wake_up(&qends->endinfo.fileinfo.writeq);
+                   #ifdef CAN_ENABLE_KERN_FASYNC
+                       /* Asynchronous I/O processing */
+                       kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_OUT);
+                   #endif /*CAN_ENABLE_KERN_FASYNC*/
+                       break;
+               case CANQUEUE_NOTIFY_PROC:
+//                     wake_up(&qends->endinfo.fileinfo.readq);
+                   #ifdef CAN_ENABLE_KERN_FASYNC
+                       /* Asynchronous I/O processing */
+                       kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_IN);
+                   #endif /*CAN_ENABLE_KERN_FASYNC*/
+                       break;
+               case CANQUEUE_NOTIFY_NOUSR:
+//                     wake_up(&qends->endinfo.fileinfo.readq);
+//                     wake_up(&qends->endinfo.fileinfo.writeq);
+//                     wake_up(&qends->endinfo.fileinfo.emptyq);
+                       break;
+               case CANQUEUE_NOTIFY_DEAD_WANTED:
+               case CANQUEUE_NOTIFY_DEAD:
+                       if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
+                               canque_edge_decref(qedge);
+                       break;
+               case CANQUEUE_NOTIFY_ATTACH:
+                       break;
+       }
+}
+
+/**
+ * canqueue_ends_init_kern - Linux userspace clients specific ends initialization
+ * @qends: pointer to the callback side ends structure
+ */
+int canqueue_ends_init_kern(struct canque_ends_t *qends)
+{
+       canqueue_ends_init_gen(qends);
+       qends->context=NULL;
+       init_waitqueue_head(&qends->endinfo.fileinfo.readq);
+       init_waitqueue_head(&qends->endinfo.fileinfo.writeq);
+       init_waitqueue_head(&qends->endinfo.fileinfo.emptyq);
+    #ifdef CAN_ENABLE_KERN_FASYNC
+       qends->endinfo.fileinfo.fasync=NULL;
+    #endif /*CAN_ENABLE_KERN_FASYNC*/
+
+       qends->notify=canqueue_notify_kern;
+       DEBUGQUE("canqueue_ends_init_kern\n");
+       return 0;
+}
+
+
+/**
+ * canque_get_inslot4id_wait_kern - find or wait for best outgoing edge and slot for given ID
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to  allocated slot
+ * @cmd: command type for slot
+ * @id: communication ID of message to send into edge
+ * @prio: optional priority of message
+ *
+ * Same as canque_get_inslot4id(), except, that it waits for free slot
+ * in case, that queue is full. Function is specific for Linux userspace clients.
+ * Return Value: If there is no usable edge negative value is returned.
+ */
+// int canque_get_inslot4id_wait_kern(struct canque_ends_t *qends,
+//     struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+//     int cmd, unsigned long id, int prio)
+// {
+//     int ret=-1;
+//     DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio);
+//     wait_event_interruptible((qends->endinfo.fileinfo.writeq),
+//             (ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1);
+//     return ret;
+// }
+
+/**
+ * canque_get_outslot_wait_kern - receive or wait for ready slot for given ends
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to received slot
+ *
+ * The same as canque_test_outslot(), except it waits in the case, that there is
+ * no ready slot for given ends. Function is specific for Linux userspace clients.
+ * Return Value: Negative value informs, that there is no ready output
+ *     slot for given ends. Positive value is equal to the command
+ *     slot has been allocated by the input side.
+ */
+// int canque_get_outslot_wait_kern(struct canque_ends_t *qends,
+//     struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
+// {
+//     int ret=-1;
+//     DEBUGQUE("canque_get_outslot_wait_kern\n");
+//     wait_event_interruptible((qends->endinfo.fileinfo.readq),
+//             (ret=canque_test_outslot(qends,qedgep,slotp))!=-1);
+//     return ret;
+// }
+
+/**
+ * canque_sync_wait_kern - wait for all slots processing
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Functions waits for ends transition into empty state.
+ * Return Value: Positive value indicates, that edge empty state has been reached.
+ *     Negative or zero value informs about interrupted wait or other problem.
+ */
+// int canque_sync_wait_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+// {
+//     int ret=-1;
+//     DEBUGQUE("canque_sync_wait_kern\n");
+//     wait_event_interruptible((qends->endinfo.fileinfo.emptyq),
+//             (ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0));
+//     return ret;
+// }
+
+
+/**
+ * canque_fifo_init_kern - initialize one CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ * @slotsnr: number of requested slots
+ *
+ * Return Value: The negative value indicates, that there is no memory
+ *     to allocate space for the requested number of the slots.
+ */
+int canque_fifo_init_kern(struct canque_fifo_t *fifo, int slotsnr)
+{
+       int size;
+       if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
+       size=sizeof(struct canque_slot_t)*slotsnr;
+       fifo->entry=malloc(size);
+       if(!fifo->entry) return -1;
+       fifo->slotsnr=slotsnr;
+       return canque_fifo_init_slots(fifo);
+}
+
+/**
+ * canque_fifo_done_kern - frees slots allocated for CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ */
+int canque_fifo_done_kern(struct canque_fifo_t *fifo)
+{
+       if(fifo->entry)
+               free(fifo->entry);
+       fifo->entry=NULL;
+       return 1;
+}
+
+
+/**
+ * canque_new_edge_kern - allocate new edge structure in the Linux kernel context
+ * @slotsnr: required number of slots in the newly allocated edge structure
+ *
+ * Return Value: Returns pointer to allocated slot structure or %NULL if
+ *     there is not enough memory to process operation.
+ */
+struct canque_edge_t *canque_new_edge_kern(int slotsnr)
+{
+       struct canque_edge_t *qedge;
+       qedge = (struct canque_edge_t *)malloc(sizeof(struct canque_edge_t));
+       if(qedge == NULL) return NULL;
+
+       memset(qedge,0,sizeof(struct canque_edge_t));
+       can_spin_lock_init(&qedge->fifo.fifo_lock);
+       if(canque_fifo_init_kern(&qedge->fifo, slotsnr)<0){
+               free(qedge);
+               DEBUGQUE("canque_new_edge_kern failed\n");
+               return NULL;
+       }
+       atomic_set(&qedge->edge_used,1);
+       qedge->filtid = 0;
+       qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
+       qedge->edge_prio = 0;
+    #ifdef CAN_DEBUG
+       /* not exactly clean, but enough for debugging */
+       atomic_inc(&edge_num_cnt);
+       qedge->edge_num=atomic_read(&edge_num_cnt);
+    #endif /* CAN_DEBUG */
+       DEBUGQUE("canque_new_edge_kern %d\n",qedge->edge_num);
+       return qedge;
+}
+
+#ifdef USE_SYNC_DISCONNECT_EDGE_KERN
+
+/*not included in doc
+ * canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: pointer to edge
+ *
+ * Same as canqueue_disconnect_edge(), but tries to wait for state with zero
+ * use counter.
+ * Return Value: Negative value means, that edge is used and cannot
+ *     be disconnected yet. Operation has to be delayed.
+ */
+int canqueue_disconnect_edge_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge)
+{
+       canque_fifo_set_fl(&qedge->fifo,BLOCK);
+       DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num);
+       if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){
+               canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD);
+
+               if(atomic_read(&qedge->edge_used)>0)
+                       atomic_dec(&qedge->edge_used);
+
+               DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num);
+               wait_event((qends->endinfo.fileinfo.emptyq),
+                       (canqueue_disconnect_edge(qedge)>=0));
+
+               /*set_current_state(TASK_UNINTERRUPTIBLE);*/
+               /*schedule_timeout(HZ);*/
+               return 0;
+       } else {
+               DEBUGQUE("canqueue_disconnect_edge_kern cannot set DEAD\n");
+               return -1;
+       }
+}
+
+
+int canqueue_disconnect_list_kern(struct canque_ends_t *qends, struct list_head *list)
+{
+       struct canque_edge_t *edge;
+       can_spin_irqflags_t flags;
+       for(;;){
+               can_spin_lock_irqsave(&qends->ends_lock,flags);
+               if(list_empty(list)){
+                       can_spin_unlock_irqrestore(&qends->ends_lock,flags);
+                       return 0;
+               }
+               if(list == &qends->inlist)
+                       edge=list_entry(list->next,struct canque_edge_t,inpeers);
+               else
+                       edge=list_entry(list->next,struct canque_edge_t,outpeers);
+               atomic_inc(&edge->edge_used);
+               can_spin_unlock_irqrestore(&qends->ends_lock,flags);
+               if(canqueue_disconnect_edge_kern(qends, edge)>=0) {
+                       /* Free edge memory */
+                       canque_fifo_done_kern(&edge->fifo);
+                       free(edge);
+               }else{
+                       canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+                       canque_edge_decref(edge);
+                       DEBUGQUE("canqueue_disconnect_list_kern in troubles\n");
+                       DEBUGQUE("the edge %d has usage count %d and flags %ld\n",edge->edge_num,atomic_read(&edge->edge_used),edge->fifo.fifo_flags);
+                       return -1;
+               }
+       }
+}
+
+#endif /*USE_SYNC_DISCONNECT_EDGE_KERN*/
+
+
+// int canqueue_ends_sync_all_kern(struct canque_ends_t *qends)
+// {
+//     struct canque_edge_t *qedge;
+//
+//     canque_for_each_inedge(qends, qedge){
+//             DEBUGQUE("canque_sync_wait_kern called for edge %d\n",qedge->edge_num);
+//             canque_sync_wait_kern(qends, qedge);
+//     }
+//     return 0;
+// }
+
+
+void canqueue_ends_dispose_postpone(struct canque_ends_t *qends)
+{
+       can_spin_irqflags_t flags;
+
+       can_spin_lock_irqsave(&canque_dead_func_lock, flags);
+       qends->ends_flags |= CAN_ENDSF_DEAD;
+       list_add(&qends->dead_peers,&canque_dead_ends);
+       can_spin_unlock_irqrestore(&canque_dead_func_lock, flags);
+       canque_dead_func(0);
+//     canque_dead_tasklet_schedule();
+}
+
+
+/**
+ * canqueue_ends_dispose_kern - finalizing of the ends structure for Linux kernel clients
+ * @qends: pointer to ends structure
+ * @sync: flag indicating, that user wants to wait for processing of all remaining
+ *     messages
+ *
+ * Return Value: Function should be designed such way to not fail.
+ */
+// int canqueue_ends_dispose_kern(struct canque_ends_t *qends, int sync)
+// {
+//     int delayed;
+//
+//     DEBUGQUE("canqueue_ends_dispose_kern\n");
+//     canqueue_block_inlist(qends);
+//     canqueue_block_outlist(qends);
+//
+//     /*Wait for sending of all pending messages in the output FIFOs*/
+//     if(sync)
+//             canqueue_ends_sync_all_kern(qends);
+//
+//     /* Finish or kill all outgoing edges listed in inends */
+//     delayed=canqueue_ends_kill_inlist(qends, 1);
+//     /* Kill all incoming edges listed in outends */
+//     delayed|=canqueue_ends_kill_outlist(qends);
+//
+// //  wake_up(&qends->endinfo.fileinfo.readq);
+// //  wake_up(&qends->endinfo.fileinfo.writeq);
+// //  wake_up(&qends->endinfo.fileinfo.emptyq);
+//
+//     if(delayed){
+//             canqueue_ends_dispose_postpone(qends);
+//
+//             DEBUGQUE("canqueue_ends_dispose_kern delayed\n");
+//             return 1;
+//     }
+//
+//     free(qends);
+//     DEBUGQUE("canqueue_ends_dispose_kern finished\n");
+//     return 0;
+// }
+
+void canqueue_kern_initialize()
+{
+       can_spin_lock_init(&canque_dead_func_lock);
+}
diff --git a/embedded/app/usbcan/can_queue.c b/embedded/app/usbcan/can_queue.c
new file mode 100644 (file)
index 0000000..9815fd0
--- /dev/null
@@ -0,0 +1,750 @@
+/* can_queue.c - CAN message queues
+ * Linux CAN-bus device driver.
+ * New CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysdep.h"
+#include "./can/can_queue.h"
+
+/*
+ * Modifies Tx message processing
+ *  0 .. local message processing disabled
+ *  1 .. local messages disabled by default but can be enabled by canque_set_filt
+ *  2 .. local messages enabled by default, can be disabled by canque_set_filt
+ */
+extern int processlocal;
+
+atomic_t edge_num_cnt;
+
+// #define CAN_DEBUG
+#undef CAN_DEBUG
+
+#ifdef CAN_DEBUG
+       #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\
+       ##args)
+
+#else
+       #define DEBUGQUE(fmt,args...)
+#endif
+
+#define CANQUE_ROUNDROB 1
+
+
+/**
+ * canque_fifo_flush_slots - free all ready slots from the FIFO
+ * @fifo: pointer to the FIFO structure
+ *
+ * The caller should be prepared to handle situations, when some
+ * slots are held by input or output side slots processing.
+ * These slots cannot be flushed or their processing interrupted.
+ *
+ * Return Value: The nonzero value indicates, that queue has not been
+ *     empty before the function call.
+ */
+int canque_fifo_flush_slots(struct canque_fifo_t *fifo)
+{
+       int ret;
+       can_spin_irqflags_t flags;
+       struct canque_slot_t *slot;
+       can_spin_lock_irqsave(&fifo->fifo_lock, flags);
+       slot=fifo->head;
+       if(slot){
+               *fifo->tail=fifo->flist;
+               fifo->flist=slot;
+               fifo->head=NULL;
+               fifo->tail=&fifo->head;
+       }
+       canque_fifo_clear_fl(fifo,FULL);
+       ret=canque_fifo_test_and_set_fl(fifo,EMPTY)?0:1;
+       can_spin_unlock_irqrestore(&fifo->fifo_lock, flags);
+       return ret;
+}
+
+
+/**
+ * canque_fifo_init_slots - initializes slot chain of one CAN FIFO
+ * @fifo: pointer to the FIFO structure
+ *
+ * Return Value: The negative value indicates, that there is no memory
+ *     to allocate space for the requested number of the slots.
+ */
+int canque_fifo_init_slots(struct canque_fifo_t *fifo)
+{
+       struct canque_slot_t *slot;
+       int slotsnr=fifo->slotsnr;
+       if(!fifo->entry || !slotsnr) return -1;
+       slot=fifo->entry;
+       fifo->flist=slot;
+       while(--slotsnr){
+               slot->next=slot+1;
+               slot++;
+       }
+       slot->next=NULL;
+       fifo->head=NULL;
+       fifo->tail=&fifo->head;
+       canque_fifo_set_fl(fifo,EMPTY);
+       return 1;
+}
+
+/* atomic_dec_and_test(&qedge->edge_used);
+ void atomic_inc(&qedge->edge_used);
+ list_add_tail(struct list_head *new, struct list_head *head)
+ list_for_each(edge,qends->inlist);
+ list_entry(ptr, type, member)
+*/
+
+void __canque_edge_decref(struct canque_edge_t *edge)
+{
+       __canque_edge_decref_body(edge);
+}
+
+/**
+ * canque_get_inslot - finds one outgoing edge and allocates slot from it
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to  allocated slot
+ * @cmd: command type for slot
+ *
+ * Function looks for the first non-blocked outgoing edge in @qends structure
+ * and tries to allocate slot from it.
+ * Return Value: If there is no usable edge or there is no free slot in edge
+ *     negative value is returned.
+ */
+int canque_get_inslot(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp, int cmd)
+{
+       int ret=-2;
+       struct canque_edge_t *edge;
+
+       edge=canque_first_inedge(qends);
+       if(edge){
+               if(!canque_fifo_test_fl(&edge->fifo,BLOCK)){
+                       ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
+                       if(ret>0){
+                               *qedgep=edge;
+                               DEBUGQUE("canque_get_inslot cmd=%d found edge %d\n",cmd,edge->edge_num);
+                               return ret;
+
+                       }
+               }
+               canque_edge_decref(edge);
+       }
+       *qedgep=NULL;
+       DEBUGQUE("canque_get_inslot cmd=%d failed\n",cmd);
+       return ret;
+}
+
+/**
+ * canque_get_inslot4id - finds best outgoing edge and slot for given ID
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to  allocated slot
+ * @cmd: command type for slot
+ * @id: communication ID of message to send into edge
+ * @prio: optional priority of message
+ *
+ * Function looks for the non-blocked outgoing edge accepting messages
+ * with given ID. If edge is found, slot is allocated from that edge.
+ * The edges with non-zero mask are preferred over edges open to all messages.
+ * If more edges with mask accepts given message ID, the edge with
+ * highest priority below or equal to required priority is selected.
+ * Return Value: If there is no usable edge or there is no free slot in edge
+ *     negative value is returned.
+ */
+int canque_get_inslot4id(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp,
+       int cmd, unsigned long id, int prio)
+{
+       int ret=-2;
+       struct canque_edge_t *edge, *bestedge=NULL;
+
+       canque_for_each_inedge(qends, edge){
+               if(canque_fifo_test_fl(&edge->fifo,BLOCK))
+                       continue;
+               if((id^edge->filtid)&edge->filtmask)
+                       continue;
+               if(bestedge){
+                       if(bestedge->filtmask){
+                               if (!edge->filtmask) continue;
+                       } else {
+                               if(edge->filtmask){
+                                       canque_edge_decref(bestedge);
+                                       bestedge=edge;
+                                       canque_edge_incref(bestedge);
+                                       continue;
+                               }
+                       }
+                       if(bestedge->edge_prio<edge->edge_prio){
+                               if(edge->edge_prio>prio) continue;
+                       } else {
+                               if(bestedge->edge_prio<=prio) continue;
+                       }
+                       canque_edge_decref(bestedge);
+               }
+               bestedge=edge;
+               canque_edge_incref(bestedge);
+       }
+       if((edge=bestedge)!=NULL){
+               ret=canque_fifo_get_inslot(&edge->fifo, slotp, cmd);
+               if(ret>0){
+                       *qedgep=edge;
+                       DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d found edge %d\n",cmd,id,prio,edge->edge_num);
+                       return ret;
+               }
+               canque_edge_decref(bestedge);
+       }
+       *qedgep=NULL;
+       DEBUGQUE("canque_get_inslot4id cmd=%d id=%ld prio=%d failed\n",cmd,id,prio);
+       return ret;
+}
+
+
+/**
+ * canque_put_inslot - schedules filled slot for processing
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: edge slot belong to
+ * @slot: pointer to the prepared slot
+ *
+ * Puts slot previously acquired by canque_get_inslot() or canque_get_inslot4id()
+ * function call into FIFO queue and activates edge processing if needed.
+ * Return Value: Positive value informs, that activation of output end
+ *     has been necessary
+ */
+int canque_put_inslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot)
+{
+       int ret;
+       ret=canque_fifo_put_inslot(&qedge->fifo,slot);
+       if(ret) {
+               canque_activate_edge(qends,qedge);
+               canque_notify_outends(qedge,CANQUEUE_NOTIFY_PROC);
+       }
+       canque_edge_decref(qedge);
+       DEBUGQUE("canque_put_inslot for edge %d returned %d\n",qedge->edge_num,ret);
+       return ret;
+}
+
+/**
+ * canque_abort_inslot - aborts preparation of the message in the slot
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: edge slot belong to
+ * @slot: pointer to the previously allocated slot
+ *
+ * Frees slot previously acquired by canque_get_inslot() or canque_get_inslot4id()
+ * function call. Used when message copying into slot fails.
+ * Return Value: Positive value informs, that queue full state has been negated.
+ */
+int canque_abort_inslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot)
+{
+       int ret;
+       ret=canque_fifo_abort_inslot(&qedge->fifo,slot);
+       if(ret) {
+               canque_notify_outends(qedge,CANQUEUE_NOTIFY_SPACE);
+       }
+       canque_edge_decref(qedge);
+       DEBUGQUE("canque_abort_inslot for edge %d returned %d\n",qedge->edge_num,ret);
+       return ret;
+}
+
+/**
+ * canque_filter_msg2edges - sends message into all edges which accept its ID
+ * @qends: ends structure belonging to calling communication object
+ * @msg: pointer to CAN message
+ *
+ * Sends message to all outgoing edges connected to the given ends, which accepts
+ * message communication ID.
+ * Return Value: Returns number of edges message has been send to
+ */
+int canque_filter_msg2edges(struct canque_ends_t *qends, struct canmsg_t *msg)
+{
+       int destnr=0;
+       int ret;
+       unsigned long msgid;
+       struct canque_edge_t *edge;
+       struct canque_slot_t *slot;
+
+       DEBUGQUE("canque_filter_msg2edges for msg ID 0x%08lx and flags 0x%02x\n",
+                       msg->id, msg->flags);
+       msgid = canque_filtid2internal(msg->id, msg->flags);
+
+       canque_for_each_inedge(qends, edge) {
+               if(canque_fifo_test_fl(&edge->fifo,BLOCK))
+                       continue;
+               if((msgid^edge->filtid)&edge->filtmask)
+                       continue;
+               ret=canque_fifo_get_inslot(&edge->fifo, &slot, 0);
+               if(ret>0){
+                       slot->msg=*msg;
+                       destnr++;
+                       ret=canque_fifo_put_inslot(&edge->fifo,slot);
+                       if(ret) {
+                               canque_activate_edge(qends,edge);
+                               canque_notify_outends(edge,CANQUEUE_NOTIFY_PROC);
+                       }
+
+               }
+       }
+       DEBUGQUE("canque_filter_msg2edges sent msg ID %ld to %d edges\n",msg->id,destnr);
+       return destnr;
+}
+
+/**
+ * canque_test_outslot - test and retrieve ready slot for given ends
+ * @qends: ends structure belonging to calling communication object
+ * @qedgep: place to store pointer to found edge
+ * @slotp: place to store pointer to received slot
+ *
+ * Function takes highest priority active incoming edge and retrieves
+ * oldest ready slot from it.
+ * Return Value: Negative value informs, that there is no ready output
+ *     slot for given ends. Positive value is equal to the command
+ *     slot has been allocated by the input side.
+ */
+int canque_test_outslot(struct canque_ends_t *qends,
+       struct canque_edge_t **qedgep, struct canque_slot_t **slotp)
+{
+       can_spin_irqflags_t flags;
+       int prio;
+       struct canque_edge_t *edge;
+       int ret;
+
+       can_spin_lock_irqsave(&qends->ends_lock, flags);
+       for(prio=CANQUEUE_PRIO_NR;--prio>=0;){
+               while(!list_empty(&qends->active[prio])){
+                       edge=list_entry(qends->active[prio].next,struct canque_edge_t,activepeers);
+                       if(!canque_fifo_test_fl(&edge->fifo,DEAD)) {
+                               /* The first test on unlocked FIFO */
+                               if(canque_fifo_test_fl(&edge->fifo,EMPTY)) {
+                                       can_spin_lock(&edge->fifo.fifo_lock);
+                                       /* Test has to be repeated to ensure that EMPTY
+                                          state has not been nagated when locking FIFO */
+                                       if(canque_fifo_test_fl(&edge->fifo,EMPTY)) {
+                                               canque_fifo_set_fl(&edge->fifo,INACTIVE);
+                                               list_del(&edge->activepeers);
+                                               list_add(&edge->activepeers,&qends->idle);
+                                               can_spin_unlock(&edge->fifo.fifo_lock);
+                                               continue;
+                                       }
+                                       can_spin_unlock(&edge->fifo.fifo_lock);
+                               }
+                               canque_edge_incref(edge);
+                               can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+                               *qedgep=edge;
+                               DEBUGQUE("canque_test_outslot found edge %d\n",edge->edge_num);
+                               ret=canque_fifo_test_outslot(&edge->fifo, slotp);
+                               if(ret>=0)
+                                       return ret;
+
+                               canque_edge_decref(edge);
+                               can_spin_lock_irqsave(&qends->ends_lock, flags);
+                       } else {
+                               can_spin_lock(&edge->fifo.fifo_lock);
+                               canque_fifo_set_fl(&edge->fifo,INACTIVE);
+                               list_del(&edge->activepeers);
+                               list_add(&edge->activepeers,&qends->idle);
+                               can_spin_unlock(&edge->fifo.fifo_lock);
+                       }
+               }
+       }
+       can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+       *qedgep=NULL;
+//     DEBUGQUE("canque_test_outslot no ready slot\n");
+       return -1;
+}
+
+/**
+ * canque_free_outslot - frees processed output slot
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: edge slot belong to
+ * @slot: pointer to the processed slot
+ *
+ * Function releases processed slot previously acquired by canque_test_outslot()
+ * function call.
+ * Return Value: Return value informs if input side has been notified
+ *     to know about change of edge state
+ */
+int canque_free_outslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot)
+{
+       int ret;
+       can_spin_irqflags_t flags;
+       ret=canque_fifo_free_outslot(&qedge->fifo, slot);
+       if(ret&CAN_FIFOF_EMPTY){
+               canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
+       }
+       if(ret&CAN_FIFOF_FULL)
+               canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
+       can_spin_lock_irqsave(&qends->ends_lock, flags);
+       if((ret&CAN_FIFOF_EMPTY) || CANQUE_ROUNDROB ){
+               can_spin_lock(&qedge->fifo.fifo_lock);
+               if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
+                       canque_fifo_set_fl(&qedge->fifo,INACTIVE);
+                       list_del(&qedge->activepeers);
+                       list_add(&qedge->activepeers,&qends->idle);
+               } else{
+                       list_del(&qedge->activepeers);
+                       list_add_tail(&qedge->activepeers,&qends->active[qedge->edge_prio]);
+               }
+               can_spin_unlock(&qedge->fifo.fifo_lock);
+       }
+       can_spin_unlock_irqrestore(&qends->ends_lock, flags);
+       canque_edge_decref(qedge);
+       DEBUGQUE("canque_free_outslot for edge %d returned %d\n",qedge->edge_num,ret);
+       return ret;
+}
+
+/**
+ * canque_again_outslot - reschedule output slot to process it again later
+ * @qends: ends structure belonging to calling communication object
+ * @qedge: edge slot belong to
+ * @slot: pointer to the slot for re-processing
+ *
+ * Function reschedules slot previously acquired by canque_test_outslot()
+ * function call for second time processing.
+ * Return Value: Function cannot fail.
+ */
+int canque_again_outslot(struct canque_ends_t *qends,
+       struct canque_edge_t *qedge, struct canque_slot_t *slot)
+{
+       int ret;
+       ret=canque_fifo_again_outslot(&qedge->fifo, slot);
+       canque_edge_decref(qedge);
+       DEBUGQUE("canque_again_outslot for edge %d returned %d\n",qedge->edge_num,ret);
+       return ret;
+}
+
+/**
+ * canque_set_filt - sets filter for specified edge
+ * @qedge: pointer to the edge
+ * @filtid: ID to set for the edge
+ * @filtmask: mask used for ID match check
+ * @filtflags: required filer flags
+ *
+ * Return Value: Negative value is returned if edge is in the process of delete.
+ */
+int canque_set_filt(struct canque_edge_t *qedge,
+       unsigned long filtid, unsigned long filtmask, int filtflags)
+{
+       int ret;
+       can_spin_irqflags_t flags;
+
+       can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
+
+       if(!(filtflags&MSG_PROCESSLOCAL) && (processlocal<2))
+               filtflags |= MSG_LOCAL_MASK;
+
+       qedge->filtid=canque_filtid2internal(filtid, filtflags);
+       qedge->filtmask=canque_filtid2internal(filtmask, filtflags>>MSG_FILT_MASK_SHIFT);
+
+       if(canque_fifo_test_fl(&qedge->fifo,DEAD)) ret=-1;
+       else ret=canque_fifo_test_and_set_fl(&qedge->fifo,BLOCK)?1:0;
+
+       can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
+       if(ret>=0){
+               canque_notify_bothends(qedge,CANQUEUE_NOTIFY_FILTCH);
+       }
+       can_spin_lock_irqsave(&qedge->fifo.fifo_lock,flags);
+       if(!ret) canque_fifo_clear_fl(&qedge->fifo,BLOCK);
+       can_spin_unlock_irqrestore(&qedge->fifo.fifo_lock,flags);
+
+       DEBUGQUE("canque_set_filt for edge %d, ID %ld, mask %ld, flags %d returned %d\n",
+                 qedge->edge_num,filtid,filtmask,filtflags,ret);
+       return ret;
+}
+
+/**
+ * canque_flush - fluesh all ready slots in the edge
+ * @qedge: pointer to the edge
+ *
+ * Tries to flush all allocated slots from the edge, but there could
+ * exist some slots associated to edge which are processed by input
+ * or output side and cannot be flushed at this moment.
+ * Return Value: The nonzero value indicates, that queue has not been
+ *     empty before the function call.
+ */
+int canque_flush(struct canque_edge_t *qedge)
+{
+       int ret;
+       can_spin_irqflags_t flags;
+
+       ret=canque_fifo_flush_slots(&qedge->fifo);
+       if(ret){
+               canque_notify_inends(qedge,CANQUEUE_NOTIFY_EMPTY);
+               canque_notify_inends(qedge,CANQUEUE_NOTIFY_SPACE);
+               can_spin_lock_irqsave(&qedge->outends->ends_lock, flags);
+               can_spin_lock(&qedge->fifo.fifo_lock);
+               if(canque_fifo_test_fl(&qedge->fifo,EMPTY)){
+                       list_del(&qedge->activepeers);
+                       list_add(&qedge->activepeers,&qedge->outends->idle);
+               }
+               can_spin_unlock(&qedge->fifo.fifo_lock);
+               can_spin_unlock_irqrestore(&qedge->outends->ends_lock, flags);
+       }
+       DEBUGQUE("canque_flush for edge %d returned %d\n",qedge->edge_num,ret);
+       return ret;
+}
+
+/**
+ * canqueue_ends_init_gen - subsystem independent routine to initialize ends state
+ * @qends: pointer to the ends structure
+ *
+ * Return Value: Cannot fail.
+ */
+int canqueue_ends_init_gen(struct canque_ends_t *qends)
+{
+       int i;
+       qends->ends_flags=0;
+       for(i=CANQUEUE_PRIO_NR;--i>=0;){
+               INIT_LIST_HEAD(&qends->active[i]);
+       }
+       INIT_LIST_HEAD(&qends->idle);
+       INIT_LIST_HEAD(&qends->inlist);
+       INIT_LIST_HEAD(&qends->outlist);
+       can_spin_lock_init(&qends->ends_lock);
+       return 0;
+}
+
+
+/**
+ * canqueue_connect_edge - connect edge between two communication entities
+ * @qedge: pointer to edge
+ * @inends: pointer to ends the input of the edge should be connected to
+ * @outends: pointer to ends the output of the edge should be connected to
+ *
+ * Return Value: Negative value informs about failed operation.
+ */
+int canqueue_connect_edge(struct canque_edge_t *qedge, struct canque_ends_t *inends, struct canque_ends_t *outends)
+{
+       can_spin_irqflags_t flags;
+       if(qedge == NULL) return -1;
+       DEBUGQUE("canqueue_connect_edge %d\n",qedge->edge_num);
+       canque_edge_incref(qedge);
+       flags=canque_edge_lock_both_ends(inends, outends);
+       can_spin_lock(&qedge->fifo.fifo_lock);
+       qedge->inends=inends;
+       list_add(&qedge->inpeers,&inends->inlist);
+       qedge->outends=outends;
+       list_add(&qedge->outpeers,&outends->outlist);
+       list_add(&qedge->activepeers,&outends->idle);
+       can_spin_unlock(&qedge->fifo.fifo_lock);
+       canque_edge_unlock_both_ends(inends, outends, flags);
+       canque_notify_bothends(qedge, CANQUEUE_NOTIFY_ATTACH);
+
+       if(canque_fifo_test_and_set_fl(&qedge->fifo, READY))
+               canque_edge_decref(qedge);
+       return 0;
+}
+
+/**
+ * canqueue_disconnect_edge - disconnect edge from communicating entities
+ * @qedge: pointer to edge
+ *
+ * Return Value: Negative value means, that edge is used by somebody
+ *     other and cannot be disconnected. Operation has to be delayed.
+ */
+int canqueue_disconnect_edge(struct canque_edge_t *qedge)
+{
+       int ret;
+       can_spin_irqflags_t flags;
+       struct canque_ends_t *inends, *outends;
+
+       inends=qedge->inends;
+       outends=qedge->outends;
+
+       if(inends && outends) {
+               flags=canque_edge_lock_both_ends(inends, outends);
+       } else {
+               DEBUGQUE("canqueue_disconnect_edge called with not fully connected edge");
+               if(inends) can_spin_lock_irqsave(&inends->ends_lock,flags);
+               if(outends) can_spin_lock(&outends->ends_lock);
+               flags=0;
+       }
+
+       can_spin_lock(&qedge->fifo.fifo_lock);
+       if(atomic_read(&qedge->edge_used)==0) {
+               if(qedge->outends){
+                       list_del(&qedge->activepeers);
+                       mb(); /* memory barrier for list_empty use in canque_dead_func */
+                       list_del(&qedge->outpeers);
+                       qedge->outends=NULL;
+               }
+               if(qedge->inends){
+                       list_del(&qedge->inpeers);
+                       qedge->inends=NULL;
+               }
+               ret=1;
+       } else ret=-1;
+       can_spin_unlock(&qedge->fifo.fifo_lock);
+
+       if(inends && outends) {
+               canque_edge_unlock_both_ends(inends, outends, flags);
+       } else {
+               if(outends) can_spin_unlock(&outends->ends_lock);
+               if(inends) can_spin_unlock_irqrestore(&inends->ends_lock,flags);
+       }
+
+       DEBUGQUE("canqueue_disconnect_edge %d returned %d\n",qedge->edge_num,ret);
+       return ret;
+}
+
+
+/**
+ * canqueue_block_inlist - block slot allocation of all outgoing edges of specified ends
+ * @qends: pointer to ends structure
+ */
+void canqueue_block_inlist(struct canque_ends_t *qends)
+{
+       struct canque_edge_t *edge;
+
+        canque_for_each_inedge(qends, edge) {
+               canque_fifo_set_fl(&edge->fifo,BLOCK);
+       }
+}
+
+
+/**
+ * canqueue_block_outlist - block slot allocation of all incoming edges of specified ends
+ * @qends: pointer to ends structure
+ */
+void canqueue_block_outlist(struct canque_ends_t *qends)
+{
+       struct canque_edge_t *edge;
+
+        canque_for_each_outedge(qends, edge) {
+               canque_fifo_set_fl(&edge->fifo,BLOCK);
+       }
+}
+
+
+/**
+ * canqueue_ends_kill_inlist - sends request to die to all outgoing edges
+ * @qends: pointer to ends structure
+ * @send_rest: select, whether already allocated slots should be processed
+ *     by FIFO output side
+ *
+ * Return Value: Non-zero value means, that not all edges could be immediately
+ *     disconnected and that ends structure memory release has to be delayed
+ */
+int canqueue_ends_kill_inlist(struct canque_ends_t *qends, int send_rest)
+{
+       struct canque_edge_t *edge;
+
+       canque_for_each_inedge(qends, edge){
+               canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+               if(send_rest){
+                       canque_edge_incref(edge);
+                       if(!canque_fifo_test_and_set_fl(&edge->fifo, FREEONEMPTY)){
+                               if(!canque_fifo_test_fl(&edge->fifo, EMPTY))
+                                       continue;
+                               if(!canque_fifo_test_and_clear_fl(&edge->fifo, FREEONEMPTY))
+                                       continue;
+                       }
+                       canque_edge_decref(edge);
+               }
+       }
+       return list_empty(&qends->inlist)?0:1;
+}
+
+
+/**
+ * canqueue_ends_kill_outlist - sends request to die to all incoming edges
+ * @qends: pointer to ends structure
+ *
+ * Return Value: Non-zero value means, that not all edges could be immediately
+ *     disconnected and that ends structure memory release has to be delayed
+ */
+int canqueue_ends_kill_outlist(struct canque_ends_t *qends)
+{
+       struct canque_edge_t *edge;
+
+       canque_for_each_outedge(qends, edge){
+               canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED);
+       }
+       return list_empty(&qends->outlist)?0:1;
+}
+
+
+/**
+ * canqueue_ends_filt_conjuction - computes conjunction of incoming edges filters filters
+ * @qends: pointer to ends structure
+ * @filt: pointer the filter structure filled by computed filters conjunction
+ *
+ * Return Value: Number of incoming edges
+ */
+int canqueue_ends_filt_conjuction(struct canque_ends_t *qends, struct canfilt_t *filt)
+{
+       struct canque_edge_t *edge;
+       int cnt=0;
+       unsigned long filtid=0;
+       unsigned long filtmask=~0;
+       unsigned long local_only=canque_filtid2internal(0,MSG_LOCAL);
+
+       canque_for_each_inedge(qends, edge){
+               /* skip edges processing only local messages */
+               if(edge->filtid & edge->filtmask & local_only)
+                       continue;
+
+               if(!cnt++)
+                       filtid = edge->filtid;
+               else
+                       filtmask &= ~(filtid ^ edge->filtid);
+
+               filtmask &= edge->filtmask;
+       }
+
+       filt->id = filtid & MSG_ID_MASK;
+       filt->mask = filtmask & MSG_ID_MASK;
+       filtid >>= 28;
+       filtmask >>= 28;
+       filt->flags = filtid & MSG_EXT;
+       if(filtmask & (MSG_EXT))
+               filt->flags |= MSG_EXT_MASK;
+       if(filtid & (MSG_RTR<<1))
+               filt->flags |= MSG_RTR<<1;
+       if(filtmask & (MSG_RTR<<1))
+               filt->flags |= MSG_RTR_MASK;
+       return cnt;
+}
+
+
+/**
+ * canqueue_ends_flush_inlist - flushes all messages in incoming edges
+ * @qends: pointer to ends structure
+ *
+ * Return Value: Negative value informs about unsuccessful result
+ */
+int canqueue_ends_flush_inlist(struct canque_ends_t *qends)
+{
+       struct canque_edge_t *edge;
+
+       canque_for_each_inedge(qends, edge){
+               canque_flush(edge);
+       }
+       return 0;
+}
+
+
+/**
+ * canqueue_ends_flush_outlist - flushes all messages in outgoing edges
+ * @qends: pointer to ends structure
+ *
+ * Return Value: Negative value informs about unsuccessful result
+ */
+int canqueue_ends_flush_outlist(struct canque_ends_t *qends)
+{
+       struct canque_edge_t *edge;
+
+       canque_for_each_outedge(qends, edge){
+               canque_flush(edge);
+       }
+       return 0;
+}
+
+
+
+
diff --git a/embedded/app/usbcan/devcommon.c b/embedded/app/usbcan/devcommon.c
new file mode 100644 (file)
index 0000000..eada97b
--- /dev/null
@@ -0,0 +1,131 @@
+/* devcommon.c - common device code
+ * Linux CAN-bus device driver.
+ * New CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysdep.h"
+#include "./can/can_queue.h"
+#include "./can/main.h"
+#include "./can/devcommon.h"
+
+#ifdef CAN_WITH_RTL
+static inline
+void canqueue_wake_chip_worker(struct canque_ends_t *qends, struct canchip_t *chip, struct msgobj_t *obj)
+{
+       if(qends->endinfo.chipinfo.worker_thread){
+               can_msgobj_set_fl(obj,WORKER_WAKE);
+               pthread_kill(qends->endinfo.chipinfo.worker_thread,RTL_SIGNAL_WAKEUP);
+               rtl_schedule();
+       } else {
+               set_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags);
+               if(chip->worker_thread) {
+                       set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
+                       pthread_kill(chip->worker_thread,RTL_SIGNAL_WAKEUP);
+                       rtl_schedule();
+               }
+       }
+}
+
+#endif /*CAN_WITH_RTL*/
+
+
+/**
+ * canqueue_notify_chip - notification callback handler for CAN chips ends of queues
+ * @qends: pointer to the callback side ends structure
+ * @qedge: edge which invoked notification
+ * @what: notification type
+ *
+ * This function has to deal with more possible cases. It can be called from
+ * the kernel or interrupt context for Linux only compilation of driver.
+ * The function can be called from kernel context or RT-Linux thread context
+ * for mixed mode Linux/RT-Linux compilation.
+ */
+void canqueue_notify_chip(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
+{
+       struct canchip_t *chip=qends->endinfo.chipinfo.chip;
+       struct msgobj_t *obj=qends->endinfo.chipinfo.msgobj;
+
+       DEBUGMSG("canqueue_notify_chip for edge %d and event %d\n",qedge->edge_num,what);
+       switch(what){
+               /*case CANQUEUE_NOTIFY_EMPTY:*/
+               /*case CANQUEUE_NOTIFY_SPACE:*/
+               /*case CANQUEUE_NOTIFY_NOUSR:
+                       wake_up(&qends->endinfo.chipinfo.daemonq);
+                       break;*/
+               case CANQUEUE_NOTIFY_PROC:
+                   #ifndef CAN_WITH_RTL
+                       /*wake_up(&qends->endinfo.chipinfo.daemonq);*/
+                       chip->chipspecops->wakeup_tx(chip, obj);
+                   #else /*CAN_WITH_RTL*/
+                       can_msgobj_set_fl(obj,TX_REQUEST);
+                       canqueue_wake_chip_worker(qends, chip, obj);
+                   #endif /*CAN_WITH_RTL*/
+                       break;
+               case CANQUEUE_NOTIFY_DEAD_WANTED:
+               case CANQUEUE_NOTIFY_DEAD:
+                       if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
+                               canque_edge_decref(qedge);
+                       break;
+               case CANQUEUE_NOTIFY_ATTACH:
+                       break;
+               case CANQUEUE_NOTIFY_FILTCH:
+                       if(!chip->chipspecops->filtch_rq)
+                               break;
+                   #ifndef CAN_WITH_RTL
+                       chip->chipspecops->filtch_rq(chip, obj);
+                   #else /*CAN_WITH_RTL*/
+                       can_msgobj_set_fl(obj,FILTCH_REQUEST);
+                       canqueue_wake_chip_worker(qends, chip, obj);
+                   #endif /*CAN_WITH_RTL*/
+
+                       break;
+       }
+}
+
+
+/**
+ * canqueue_ends_init_chip - CAN chip specific ends initialization
+ * @qends: pointer to the ends structure
+ * @chip: pointer to the corresponding CAN chip structure
+ * @obj: pointer to the corresponding message object structure
+ */
+int canqueue_ends_init_chip(struct canque_ends_t *qends, struct canchip_t *chip, struct msgobj_t *obj)
+{
+       int ret;
+       ret=canqueue_ends_init_gen(qends);
+       if(ret<0) return ret;
+
+       qends->context=NULL;
+    #ifndef CAN_WITH_RTL
+       init_waitqueue_head(&qends->endinfo.chipinfo.daemonq);
+    #endif /*CAN_WITH_RTL*/
+       qends->endinfo.chipinfo.chip=chip;
+       qends->endinfo.chipinfo.msgobj=obj;
+       qends->notify=canqueue_notify_chip;
+
+       DEBUGMSG("canqueue_ends_init_chip\n");
+       return 0;
+}
+
+
+/**
+ * canqueue_ends_done_chip - finalizing of the ends structure for CAN chips
+ * @qends: pointer to ends structure
+ *
+ * Return Value: Function should be designed such way to not fail.
+ */
+int canqueue_ends_done_chip(struct canque_ends_t *qends)
+{
+       int delayed;
+
+       /* Finish or kill all outgoing edges listed in inends */
+       delayed=canqueue_ends_kill_inlist(qends, 1);
+       /* Kill all incoming edges listed in outends */
+       delayed|=canqueue_ends_kill_outlist(qends);
+
+       return delayed;
+}
diff --git a/embedded/app/usbcan/finish.c b/embedded/app/usbcan/finish.c
new file mode 100644 (file)
index 0000000..fad2c05
--- /dev/null
@@ -0,0 +1,136 @@
+/* finish.c - finalization of the driver operation
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysless.h"
+#include "./can/main.h"
+#include "./can/devcommon.h"
+#include "./can/finish.h"
+#include "./can/setup.h"
+
+
+/**
+ * msgobj_done - destroys one CAN message object
+ * @obj: pointer to CAN message object structure
+ */
+void msgobj_done(struct msgobj_t *obj)
+{
+       int delayed=0;
+       if(obj->qends) {
+               delayed=canqueue_ends_done_chip(obj->qends);
+               if(delayed < 0)
+                       CANMSG("msgobj_done: problem with chip queue ends\n");
+       }
+
+       if((obj->hostchip) && (obj->object>0)) {
+               if(obj->hostchip->msgobj[obj->object-1] == obj)
+                       obj->hostchip->msgobj[obj->object-1]=NULL;
+               else
+                       CANMSG("msgobj_done: not registered in the canchip_t\n");
+               obj->hostchip=NULL;
+       }
+
+       if((obj->minor>=0)) {
+               if(objects_p[obj->minor] == obj)
+                       objects_p[obj->minor] = NULL;
+               else
+                       CANMSG("msgobj_done: not registered as minor\n");
+       }
+
+//     del_timer_sync(&obj->tx_timeout);
+
+       if(obj->qends) {
+               /*delayed free could be required there in the future,
+                 actual use patter cannot generate such situation*/
+               if(!delayed) {
+                       free(obj->qends);
+               }
+       }
+       obj->qends=NULL;
+}
+
+
+/**
+ * canchip_done - destroys one CAN chip representation
+ * @chip: pointer to CAN chip structure
+ */
+void canchip_done(struct canchip_t *chip)
+{
+
+       int i;
+       struct msgobj_t *obj;
+
+       if(chip->flags & CHIP_ATTACHED)
+               chip->chipspecops->release_chip(chip);
+
+       if((chip->hostdevice) && (chip->chip_idx>=0)) {
+               if(chip->hostdevice->chip[chip->chip_idx] == chip)
+                       chip->hostdevice->chip[chip->chip_idx] = NULL;
+               else
+                       CANMSG("canchip_done: not registered in hostdevice\n");
+       }
+
+// Not using interrupts
+//     can_chip_free_irq(chip);
+
+//     can_synchronize_irq(chip->chip_irq);
+
+       for(i=0; i<chip->max_objects; i++){
+               if((obj=chip->msgobj[i])==NULL)
+                       continue;
+               msgobj_done(obj);
+               free(obj);
+       }
+
+       free(chip->chipspecops);
+       chip->chipspecops=NULL;
+
+}
+
+/**
+ * candevice_done - destroys representation of one CAN device/board
+ * @candev: pointer to CAN device/board structure
+ */
+void candevice_done(struct candevice_t *candev)
+{
+       int i;
+       struct canchip_t *chip;
+
+       for(i=0; i<candev->nr_all_chips; i++){
+               if((chip=candev->chip[i])==NULL)
+                       continue;
+               canchip_done(chip);
+               free(chip);
+
+       }
+       if(candev->flags & CANDEV_IO_RESERVED) {
+               candev->hwspecops->release_io(candev);
+               candev->flags &= ~CANDEV_IO_RESERVED;
+       }
+       free(candev->hwspecops);
+       candev->hwspecops=NULL;
+}
+
+/**
+ * candevice_done - destroys representation of all CAN devices/boards
+ * @canhw: pointer to the root of all CAN hardware representation
+ */
+void canhardware_done(struct canhardware_t *canhw)
+{
+       int i;
+       struct candevice_t *candev;
+
+       for(i=0; i<canhw->nr_boards; i++){
+               if((candev=canhw->candevice[i])==NULL)
+                       continue;
+               candevice_done(candev);
+               free(candev);
+       }
+
+}
diff --git a/embedded/app/usbcan/main.c b/embedded/app/usbcan/main.c
new file mode 100644 (file)
index 0000000..fd12f59
--- /dev/null
@@ -0,0 +1,462 @@
+#include <stdio.h>
+#include <string.h>
+#include <cpu_def.h>
+#include <system_def.h>
+#include <lt_timer.h>
+#include <local_config.h>
+#include <usb/usbdebug.h>
+#include <usb/usb.h>
+#include <usb/lpc.h>
+#include <usb/usb_srq.h>
+#include <mem_loc.h>
+#include <keyval_id.h>
+#include <hal_machperiph.h>
+#include <keyval_loc.h>
+#include <lpciap.h>
+#include <lpciap_kvpb.h>
+
+#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+  #include <byteswap.h>
+#endif
+
+#include "./can/can.h"
+#include "./can/sja1000p.h"
+#include "./can/main.h"
+
+// #include "./can/can_sysdep.h"
+#include "./can/modparms.h"
+#include "./can/devcommon.h"
+
+#include "./can/ul_usb1.h"
+//#include "./can/setup.h"
+
+#include "./usb/usb_vend.h"
+
+#define MASK_EP1RX  0x01
+#define MASK_EP1TX  0x02
+
+#define CAN_OP_MASK 0x80
+#define CAN_OP_READ 0x80
+#define CAN_OP_WRITE 0x00
+
+#ifdef USB_MAX_PACKET
+       #undef USB_MAX_PACKET
+       #define USB_MAX_PACKET 16
+#endif
+/***********************************************************************
+ * Note:
+ * Comparing to LinCAN, there is no need to sleep for processes
+ * because the degree of filling of fifo from the client side
+ * is solved in main cycle (no new messages are accepted when full)
+ * and on the server side by speed of USB interface. FIFO in edge
+ * from SJA chip to USB interface should never be filled.
+ ***********************************************************************/
+
+/***********************************************************************
+ * Note:
+ * Code is wittingly complex in order to ease future changes in hardware
+ *¬†configuration and to make it as much similar as the code of LinCAN
+ ***********************************************************************/
+
+LT_TIMER_DEC(lt_10msec)
+LT_TIMER_IMP(lt_10msec)
+LT_TIMER_DEC(lt_100msec)
+LT_TIMER_IMP(lt_100msec)
+LT_TIMER_DEC(lt_2sec)
+LT_TIMER_IMP(lt_2sec)
+
+typedef void (*FNC)(); //function ptr
+
+/***********************************************************************
+       * global variables
+       ***********************************************************************/
+
+
+usb_device_t usb_device;
+
+usb_ep_t eps[2];
+unsigned char ep1_rx_buff[USB_MAX_PACKET];
+unsigned char ep1_tx_buff[USB_MAX_PACKET];
+uint8_t timer_str,timer_rx_off,timer_tx_off,timer_configured;
+volatile uint8_t bootloader_run;
+
+uint8_t vendor_ret;
+
+int processlocal;
+
+int baudrate[MAX_TOT_CHIPS];
+struct canhardware_t canhardware;
+struct canhardware_t *hardware_p=&canhardware;
+struct canchip_t *chips_p[MAX_TOT_CHIPS];
+struct msgobj_t *objects_p[MAX_TOT_MSGOBJS];
+
+struct canuser_t *canuser;
+
+extern int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate);
+extern int register_chip_struct(struct canchip_t *chip, int minorbase);
+extern int register_obj_struct(struct msgobj_t *obj, int minorbase);
+
+/***********************************************************************
+ * IF SOMETHING BAD HAPPENED
+ ***********************************************************************/
+
+int sys_err(){
+  unsigned char i=0;
+
+  while(1) {
+    if (lt_100msec_expired(100)) {
+      i++;
+      if (i&1) {
+        SET_OUT_PIN(LED_PORT,LED_ERR);
+      } else {
+        CLR_OUT_PIN(LED_PORT,LED_ERR);
+      }
+     #ifdef WATCHDOG_ENABLED
+      watchdog_feed();
+     #endif /* WATCHDOG_ENABLED */
+    }
+  }
+}
+
+/***********************************************************************
+ * Routine for visible LED blinking (on USB transmission)
+ ***********************************************************************/
+
+void timer_10ms(void)
+{
+  if (timer_tx_off!=0) timer_tx_off--;
+  else SET_OUT_PIN(LED_PORT,LED1_BIT);
+  if (timer_rx_off!=0) timer_rx_off--;
+  else SET_OUT_PIN(LED_PORT,LED2_BIT);
+/*  if (timer_configured!=0) timer_configured--;
+  else {
+    timer_configured=20;
+               CLR_OUT_PIN(LED_PORT,LED1_BIT);
+               CLR_OUT_PIN(LED_PORT,LED2_BIT);
+               timer_rx_off=timer_tx_off=5;
+  }*/
+}
+
+/***********************************************************************
+ * Main routine
+ ***********************************************************************/
+
+int main(void)
+{
+       struct candevice_t *candev;
+       struct canchip_t *chip=NULL;
+       struct msgobj_t *obj;
+       struct canque_ends_t *qends;
+       struct canque_edge_t *edge,*qedge;
+       struct canque_slot_t *slot;
+       struct canmsg_t canmsg;
+       can_spin_irqflags_t iflags;
+
+       int chipnr,bd;
+       int i,size,m=0;
+
+       CANMSG("Starting USBCAN module firmware...\n");
+
+//     volatile int i=0;
+       bootloader_run=0;
+       /***********************************/
+       lt_10msec_init();
+       lt_100msec_init();
+       lt_2sec_init();
+
+       SET_OUT_PIN(LED_PORT,LED_ERR);
+       CLR_OUT_PIN(LED_PORT,LED_GP);
+
+       if (USB_MAX_PACKET<16){
+               CANMSG("Maximum packet size less than 16B (is %dB)\n",USB_MAX_PACKET);
+               sys_err();
+       }
+
+       /***********************************************************************
+        * CAN device initialization - device side (adapted from LinCAN setup.c)
+        ***********************************************************************/
+
+       can_init();
+
+       DEBUGMSG("Initiating CAN device initialization\n");
+       baudrate[0]=1000;
+
+       canqueue_kern_initialize();
+
+       hardware_p->nr_boards=1;
+
+       candev=(struct candevice_t *)malloc(sizeof(struct candevice_t));
+       if (!candev){
+               CANMSG("No space left in memory\n");
+               sys_err();
+       }
+       memset(candev, 0, sizeof(struct candevice_t));
+
+       hardware_p->candevice[0]=candev;
+       candev->candev_idx=0;
+       candev->io_addr=0;
+       candev->dev_base_addr=0;
+
+       candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t));
+       if (!candev->hwspecops){
+               CANMSG("No space left in memory\n");
+               sys_err();
+       }
+       memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
+
+       ul_usb1_register(candev->hwspecops);
+
+       bd=baudrate[0];
+       if (candev->hwspecops->init_hw_data(candev)){
+               CANMSG("HW data could not be initialized\n");
+               sys_err();
+       }
+       /* Alocate and initialize the chip structures */
+       for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+/*             if(chipnr<irqnum)
+                       irqsig=irq[*irq_param_idx_p+chipnr];*/
+               if (init_chip_struct(candev, chipnr, 0, bd*1000)){
+                       CANMSG("Chip structure could not be initialized\n");
+                       sys_err();
+               }
+       }
+       for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+               struct canchip_t *chip=candev->chip[chipnr];
+               int objnr;
+
+               register_chip_struct(chip, m);
+
+               for (objnr=0; objnr<chip->max_objects; objnr++) {
+                       register_obj_struct(chip->msgobj[objnr], m);
+                       if(m>=0) m++;
+               }
+       }
+       if (candev->hwspecops->request_io(candev))
+               sys_err();
+       candev->flags|=CANDEV_IO_RESERVED;
+       if (candev->hwspecops->reset(candev))
+               sys_err();
+       for(chipnr=0; chipnr<candev->nr_all_chips; chipnr++) {
+               if((chip=candev->chip[chipnr])==NULL)
+                       continue;
+
+               if(chip->chipspecops->attach_to_chip(chip)<0) {
+//                     CANMSG("Initial attach to the chip HW failed\n");
+                       sys_err();
+               }
+
+               chip->flags |= CHIP_ATTACHED;
+
+// Interrupts from chip are served in main cycle
+/*             if(can_chip_setup_irq(chip)<0) {
+//                     CANMSG("Error to setup chip IRQ\n");
+                       sys_err();
+               }*/
+       }
+
+       if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
+               if (candev->hwspecops->program_irq(candev)){
+//                     CANMSG("Error to program board interrupt\n");
+                       sys_err();
+               }
+
+       /***********************************************************************
+        * CAN device initialization - client side (adapted from LinCAN open.c)
+        ***********************************************************************/
+
+       chip=candev->chip[0];
+       obj=chip->msgobj[0];
+       atomic_inc(&obj->obj_used);
+       can_msgobj_set_fl(obj,OPENED);
+
+       if (chip->flags & CHIP_CONFIGURED)
+               DEBUGMSG("Device is already configured.\n");
+       else {
+               if (chip->chipspecops->chip_config(chip))
+                       CANMSG("Error configuring chip.\n");
+               else
+                       chip->flags |= CHIP_CONFIGURED;
+
+               if (chip->chipspecops->pre_read_config(chip,obj)<0)
+                       CANMSG("Error initializing chip for receiving\n");
+
+       } /* End of chip configuration */
+
+       canuser = (struct canuser_t *)malloc(sizeof(struct canuser_t));
+       if(canuser == NULL) sys_err();
+       canuser->flags=0;
+//     canuser->userinfo.fileinfo.file = file;
+       canuser->msgobj = obj;
+//     canuser->magic = CAN_USER_MAGIC;
+//     file->private_data = canuser;
+
+       qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t));
+       if(qends == NULL) sys_err();
+       canqueue_ends_init_kern(qends);
+       canuser->qends = qends;
+
+       /*required to synchronize with RT-Linux context*/
+       can_spin_lock_irqsave(&canuser_manipulation_lock, iflags);
+       list_add(&canuser->peers, &obj->obj_users);
+       can_spin_unlock_irqrestore(&canuser_manipulation_lock, iflags);
+
+       if(canqueue_connect_edge(edge=canque_new_edge_kern(MAX_BUF_LENGTH),
+               canuser->qends, obj->qends)<0) sys_err();
+
+       if(canqueue_connect_edge(canuser->rx_edge0=canque_new_edge_kern(MAX_BUF_LENGTH),
+               obj->qends, canuser->qends)<0) sys_err();
+       /*FIXME: more generic model should be used there*/
+       canque_edge_decref(canuser->rx_edge0);
+       canque_edge_decref(edge);
+
+
+       /***********************************************************************
+        * USB Init
+        ***********************************************************************/
+
+       memset( &usb_device, 0, sizeof( usb_device));
+       usb_device.id = 1;
+       usb_device.init = usb_lpc_init;
+       usb_debug_set_level(DEBUG_LEVEL_NONE);
+       usb_device.cntep = 3;
+       usb_device.ep = eps;
+
+       eps[0].max_packet_size = USB_MAX_PACKET;
+       eps[1].max_packet_size = USB_MAX_PACKET;
+       eps[0].epnum = 0x01;
+       eps[1].epnum = 0x81;
+       eps[0].event_mask = 0x04;
+       eps[1].event_mask = 0x08;
+       eps[0].udev = &usb_device;
+       eps[1].udev = &usb_device;
+
+  usb_device.vendor_fnc=usbcan_vendor;
+
+       usb_init(&usb_device);
+       usb_connect(&usb_device);
+       usb_device.ep_events |= MASK_EP1TX;
+
+       /***********************************************************************
+        * Start
+        ***********************************************************************/
+
+  timer_rx_off=timer_tx_off=timer_str=timer_configured=0;
+       while (1) {
+
+               usb_check_events(&usb_device);
+               usb_control_response(&usb_device);
+
+               if (!(IO0PIN&P0_SJA1000_INT_PIN)) //INT PIN is inverted
+                       chip->chipspecops->irq_handler(0,chip);
+
+               if (usb_device.ep_events & MASK_EP1RX) {  //EP1RX - data waiting to receive
+                       uint8_t val;
+                       if (canque_get_inslot(qends, &qedge, &slot, 0)>=0){ //Free slot obtained
+                               size=usb_udev_read_endpoint(&eps[0],ep1_rx_buff,16);
+                               if (size==16){
+                                       uint16_t msgflags;
+                                       uint32_t msgid;
+                                       canmsg.cob=0;
+                                       canmsg.length=*(uint8_t *)(ep1_rx_buff+1);
+                                       if (canmsg.length > CAN_MSG_LENGTH)
+                                               canmsg.length=CAN_MSG_LENGTH;
+                                       msgflags=*(uint16_t *)(ep1_rx_buff+2);
+                                       msgid=*(uint32_t *)(ep1_rx_buff+4);
+                                       #if __BYTE_ORDER == __BIG_ENDIAN
+                                               msgflags  = bswap_16( msgflags);
+                                               msgid  = bswap_32( msgid);
+                                       #endif
+                                       canmsg.flags=msgflags;
+                                       canmsg.id=msgid;
+
+                                       for (i=0;i<canmsg.length;i++){
+                                               canmsg.data[i]=*(unsigned char*)(ep1_rx_buff+8+i);
+                                       }
+                                       for (;i<CAN_MSG_LENGTH;i++){
+                                               canmsg.data[i]=0;
+                                       }
+                                       /* Automatic selection of extended format if ID>2047 */
+                                       if (canmsg.id & ~0x7ffl & MSG_ID_MASK ) canmsg.flags |= MSG_EXT;
+                                       /* has been dependent on "extended" option */
+                                       slot->msg=canmsg;
+                                       canque_put_inslot(qends, qedge, slot);
+                               }
+                               else
+                                       canque_abort_inslot(qends,qedge,slot);
+                               timer_rx_off=50;        //rosviceni diody pri prijmu
+                               CLR_OUT_PIN(LED_PORT,LED2_BIT);
+                               usb_device.ep_events &= ~MASK_EP1RX;
+                       }
+
+
+/*                     if (size==2){
+                               if (((*data)&CAN_OP_MASK)==CAN_OP_READ){ // Get data from CAN device and return to caller
+                                       can_read((*data) & 0x7F,&val);
+                                       *(data+1)=val;
+                                       usb_udev_write_endpoint(&eps[1],(unsigned char *)data,size);
+                                       timer_rx_off=50;        //rosviceni diody pri prijmu
+                                       CLR_OUT_PIN(LED_PORT,LED2_BIT);
+                                       usb_can_send=0;
+                               }
+                               if (((*data)&CAN_OP_MASK)==CAN_OP_WRITE){ // Save data to CAN device
+                                       can_write((*data)&(~CAN_OP_MASK),data+1);
+                                       timer_tx_off=50;                //rozsviceni diod pri vysilani
+                                       CLR_OUT_PIN(LED_PORT,LED1_BIT);
+                               }
+                       }*/
+               }
+
+               if(usb_device.ep_events & MASK_EP1TX){ //EP1TX - data transmitted
+                       if(canque_test_outslot(qends, &qedge, &slot)>=0){
+                               DEBUGMSG("CAN message ready to send over usb\n");
+                               uint16_t msgflags;
+                               uint32_t msgid;
+
+                               *(uint8_t *)(ep1_tx_buff)=0;
+                               *(uint8_t *)(ep1_tx_buff+1)=slot->msg.length;
+
+                               msgflags=slot->msg.flags;
+                               msgid=slot->msg.id;
+                               #if __BYTE_ORDER == __BIG_ENDIAN
+                                       msgflags  = bswap_16( msgflags);
+                                       msgid  = bswap_32( msgid);
+                               #endif
+
+                               *(uint16_t *)(ep1_tx_buff+2)=msgflags;
+                               *(uint32_t *)(ep1_tx_buff+4)=msgid;
+                               for (i=0;i<slot->msg.length;i++){
+                                       *(uint8_t *)(ep1_tx_buff+8+i)=slot->msg.data[i];
+                               }
+                               for (;i<CAN_MSG_LENGTH;i++){
+                                       *(uint8_t *)(ep1_tx_buff+8+i)=0;
+                               }
+                               usb_udev_write_endpoint(&eps[1],ep1_tx_buff,16);
+
+                               canque_free_outslot(qends, qedge, slot);
+                               timer_tx_off=50;                //rozsviceni diod pri vysilani
+                               CLR_OUT_PIN(LED_PORT,LED1_BIT);
+                               usb_device.ep_events &= ~MASK_EP1TX;
+                       }
+               }
+
+               //if (usb_can_send && )
+
+#ifdef WATCHDOG_ENABLED
+               watchdog_feed();
+#endif /* WATCHDOG_ENABLED */
+
+               /* 10ms timer */
+               if (lt_10msec_expired(10))
+                       timer_10ms();
+       }
+
+       SET_OUT_PIN(LED_PORT,LED_GP);
+       SET_OUT_PIN(LED_PORT,LED_ERR);
+
+       /* unreachable code */
+#ifdef SDCC
+       vec_jmp(0x0);  /* need to call a function from misc to correct linking */
+#endif
+       return 0;
+}
diff --git a/embedded/app/usbcan/setup.c b/embedded/app/usbcan/setup.c
new file mode 100644 (file)
index 0000000..e046c9b
--- /dev/null
@@ -0,0 +1,395 @@
+/* setup.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysless.h"
+#include "./can/main.h"
+#include "./can/devcommon.h"
+#include "./can/setup.h"
+//#include "./can/finish.h"
+
+int init_hwspecops(struct candevice_t *candev, int *irqnum_p);
+int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p);
+int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate);
+int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr);
+
+/**
+ * can_base_addr_fixup - relocates board physical memory addresses to the CPU accessible ones
+ * @candev: pointer to the previously filled device/board, chips and message objects structures
+ * @new_base: @candev new base address
+ *
+ * This function adapts base addresses of all structures of one board
+ * to the new board base address.
+ * It is required for translation between physical and virtual address mappings.
+ * This function is prepared to simplify board specific xxx_request_io() function
+ * for memory mapped devices.
+ */
+int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base)
+{
+       unsigned long offs;
+       int i, j;
+
+       offs=new_base-candev->dev_base_addr;
+       candev->dev_base_addr=new_base;
+       for(i=0;i<candev->nr_all_chips;i++){
+               candev->chip[i]->chip_base_addr += offs;
+               for(j=0;j<candev->chip[i]->max_objects;j++)
+                       candev->chip[i]->msgobj[j]->obj_base_addr += offs;
+       }
+       return 0;
+}
+
+/**
+ * can_check_dev_taken - checks if bus device description is already taken by driver
+ * @anydev:    pointer to bus specific Linux device description
+ *
+ * Returns: Returns 1 if device is already used by LinCAN driver, 0 otherwise.
+ */
+int can_check_dev_taken(void *anydev)
+{
+       int board_nr;
+       struct candevice_t *candev;
+       void *boarddev;
+
+       for (board_nr=hardware_p->nr_boards; board_nr--; ) {
+               if((candev=hardware_p->candevice[board_nr])==NULL)
+                       continue;
+               boarddev=candev->sysdevptr.anydev;
+               if(boarddev == anydev)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * register_obj_struct - registers message object into global array
+ * @obj: the initialized message object being registered
+ * @minorbase: wanted minor number, if (-1) automatically selected
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int register_obj_struct(struct msgobj_t *obj, int minorbase)
+{
+       static int next_minor=0;
+       int i;
+
+       if(minorbase>=0)
+               next_minor=minorbase;
+       if(next_minor>=MAX_TOT_MSGOBJS)
+               next_minor=0;
+       i=next_minor;
+       do{
+               if(objects_p[i]==NULL){
+                       objects_p[i]=obj;
+                       obj->minor=i;
+                       next_minor=i+1;
+                       return 0;
+               }
+               if(++i >= MAX_TOT_MSGOBJS) i=0;
+       }while(i!=next_minor);
+       obj->minor=-1;
+       return -1;
+}
+
+
+/**
+ * register_chip_struct - registers chip into global array
+ * @chip: the initialized chip structure being registered
+ * @minorbase: wanted minor number base, if (-1) automatically selected
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int register_chip_struct(struct canchip_t *chip, int minorbase)
+{
+       static int next_chip_slot=0;
+       int i;
+
+       if(next_chip_slot>=MAX_TOT_CHIPS)
+               next_chip_slot=0;
+       i=next_chip_slot;
+       do{
+               if(chips_p[i]==NULL){
+                       chips_p[i]=chip;
+
+                       next_chip_slot=i+1;
+                       return 0;
+               }
+               if(++i >= MAX_TOT_CHIPS) i=0;
+       }while(i!=next_chip_slot);
+       return -1;
+}
+
+
+
+/**
+ * init_hw_struct - initializes driver hardware description structures
+ *
+ * The function init_hw_struct() is used to initialize the hardware structure.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+// int init_hw_struct(void)
+// {
+//     int i=0;
+//     int irq_param_idx=0;
+//     int chan_param_idx=0;
+//
+//     hardware_p->nr_boards=0;
+//     while ( (hw[i] != NULL) & (i < MAX_HW_CARDS) ) {
+//             hardware_p->nr_boards++;
+//
+//             if (init_device_struct(i, &chan_param_idx, &irq_param_idx)) {
+//                     CANMSG("Error initializing candevice_t structures.\n");
+//                     return -ENODEV;
+//             }
+//             i++;
+//     }
+//
+//     return 0;
+// }
+
+/**
+ * init_device_struct - initializes single CAN device/board
+ * @card: index into @hardware_p HW description
+ * @chan_param_idx_p: pointer to the index into arrays of the CAN channel parameters
+ * @irq_param_idx_p: pointer to the index into arrays of the per CAN channel IRQ parameters
+ *
+ * The function builds representation of the one board from parameters provided
+ * in the module parameters arrays:
+ *     @hw[card] .. hardware type,
+ *     @io[card] .. base IO address,
+ *     @baudrate[chan_param_idx] .. per channel baudrate,
+ *     @minor[chan_param_idx] .. optional specification of requested channel minor base,
+ *     @irq[irq_param_idx] .. one or more board/chips IRQ parameters.
+ * The indexes are advanced after consumed parameters if the registration is successful.
+ *
+ * The hardware specific operations of the device/board are initialized by call to
+ * init_hwspecops() function. Then board data are initialized by board specific
+ * init_hw_data() function. Then chips and objects representation is build by
+ * init_chip_struct() function. If all above steps are successful, chips and
+ * message objects are registered into global arrays.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+// int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p)
+// {
+//     struct candevice_t *candev;
+//     int ret;
+//     int irqnum;
+//     int chipnr;
+//     long bd;
+//     int irqsig=-1;
+//
+//     candev=(struct candevice_t *)malloc(sizeof(struct candevice_t));
+//     if (candev==NULL)
+//             return -ENOMEM;
+//
+//         memset(candev, 0, sizeof(struct candevice_t));
+//
+//     hardware_p->candevice[card]=candev;
+//     candev->candev_idx=card;
+//
+//     candev=candev;
+//
+//     candev->hwname=hw[card];
+//     candev->io_addr=io[card];
+//     candev->dev_base_addr=io[card];
+//
+//     candev->hwspecops=(struct hwspecops_t *)malloc(sizeof(struct hwspecops_t));
+//     if (candev->hwspecops==NULL)
+//             goto error_nomem;
+//
+//     memset(candev->hwspecops, 0, sizeof(struct hwspecops_t));
+//
+//     if (init_hwspecops(candev, &irqnum))
+//             goto error_nodev;
+//
+//     if (candev->hwspecops->init_hw_data(candev))
+//             goto error_nodev;
+//
+//     /* Alocate and initialize the chip structures */
+//     for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+//
+//             if(chipnr<irqnum)
+//                     irqsig=irq[*irq_param_idx_p+chipnr];
+//
+//             bd=baudrate[*chan_param_idx_p+chipnr];
+//             if(!bd) bd=baudrate[0];
+//
+//             if ((ret=init_chip_struct(candev, chipnr, irqsig, bd*1000)))
+//                     goto error_chip;
+//     }
+//
+//
+//
+//     for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
+//             int m=minor[*chan_param_idx_p+chipnr];
+//             struct canchip_t *chip=candev->chip[chipnr];
+//             int objnr;
+//
+//             register_chip_struct(chip, m);
+//
+//             for (objnr=0; objnr<chip->max_objects; objnr++) {
+//                     register_obj_struct(chip->msgobj[objnr], m);
+//                     if(m>=0) m++;
+//             }
+//     }
+//
+//     *irq_param_idx_p += irqnum;
+//     *chan_param_idx_p += candev->nr_all_chips;
+//
+//     return 0;
+//
+//     error_nodev:
+//     ret=-ENODEV;
+//     error_chip:
+//     candevice_done(candev);
+//     goto error_both;
+//
+//     error_nomem:
+//     ret=-ENOMEM;
+//
+//     error_both:
+//     hardware_p->candevice[card]=NULL;
+//     free(candev);
+//     return ret;
+//
+// }
+
+/**
+ * init_chip_struct - initializes one CAN chip structure
+ * @candev: pointer to the corresponding CAN device/board
+ * @chipnr: index of the chip in the corresponding device/board structure
+ * @irq: chip IRQ number or (-1) if not appropriate
+ * @baudrate: baudrate in the units of 1Bd
+ *
+ * Chip structure is allocated and chip specific operations are filled by
+ * call to board specific init_chip_data() which calls chip specific
+ * fill_chipspecops(). The message objects are generated by
+ * calls to init_obj_struct() function.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate)
+{
+       struct canchip_t *chip;
+       int objnr;
+       int ret;
+
+       candev->chip[chipnr]=(struct canchip_t *)malloc(sizeof(struct canchip_t));
+       if ((chip=candev->chip[chipnr])==NULL)
+               return -ENOMEM;
+
+        memset(chip, 0, sizeof(struct canchip_t));
+
+       chip->write_register=candev->hwspecops->write_register;
+       chip->read_register=candev->hwspecops->read_register;
+
+       chip->chipspecops=malloc(sizeof(struct chipspecops_t));
+       if (chip->chipspecops==NULL)
+               return -ENOMEM;
+       memset(chip->chipspecops,0,sizeof(struct chipspecops_t));
+
+       chip->chip_idx=chipnr;
+       chip->hostdevice=candev;
+       chip->chip_irq=irq;
+       chip->baudrate=baudrate;
+       chip->flags=0x0;
+
+       if(candev->hwspecops->init_chip_data(candev,chipnr)<0)
+               return -ENODEV;
+
+       for (objnr=0; objnr<chip->max_objects; objnr++) {
+               ret=init_obj_struct(candev, chip, objnr);
+               if(ret<0) return ret;
+       }
+
+       return 0;
+}
+
+
+/**
+ * init_obj_struct - initializes one CAN message object structure
+ * @candev: pointer to the corresponding CAN device/board
+ * @hostchip: pointer to the chip containing this object
+ * @objnr: index of the builded object in the chip structure
+ *
+ * The function initializes message object structure and allocates and initializes
+ * CAN queue chip ends structure.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int objnr)
+{
+       struct canque_ends_t *qends;
+       struct msgobj_t *obj;
+       int ret;
+
+       obj=(struct msgobj_t *)malloc(sizeof(struct msgobj_t));
+       hostchip->msgobj[objnr]=obj;
+       if (obj == NULL)
+               return -ENOMEM;
+
+        memset(obj, 0, sizeof(struct msgobj_t));
+       obj->minor=-1;
+
+       atomic_set(&obj->obj_used,0);
+       INIT_LIST_HEAD(&obj->obj_users);
+//     init_timer(&obj->tx_timeout);
+
+       qends = (struct canque_ends_t *)malloc(sizeof(struct canque_ends_t));
+       if(qends == NULL) return -ENOMEM;
+       memset(qends, 0, sizeof(struct canque_ends_t));
+       obj->hostchip=hostchip;
+       obj->object=objnr+1;
+       obj->qends=qends;
+       obj->tx_qedge=NULL;
+       obj->tx_slot=NULL;
+       obj->obj_flags = 0x0;
+
+       ret=canqueue_ends_init_chip(qends, hostchip, obj);
+       if(ret<0) return ret;
+
+       ret=candev->hwspecops->init_obj_data(hostchip,objnr);
+       if(ret<0) return ret;
+
+       return 0;
+}
+
+
+/**
+ * init_hwspecops - finds and initializes board/device specific operations
+ * @candev: pointer to the corresponding CAN device/board
+ * @irqnum_p: optional pointer to the number of interrupts required by board
+ *
+ * The function searches board @hwname in the list of supported boards types.
+ * The board type specific board_register() function is used to initialize
+ * @hwspecops operations.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+// int init_hwspecops(struct candevice_t *candev, int *irqnum_p)
+// {
+//     const struct boardtype_t *brp;
+//
+//     brp = boardtype_find(candev->hwname);
+//
+//     if(!brp) {
+//             CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",candev->hwname);
+//             return -EINVAL;
+//     }
+//
+//     if(irqnum_p)
+//             *irqnum_p=brp->irqnum;
+//     brp->board_register(candev->hwspecops);
+//
+//     return 0;
+// }
diff --git a/embedded/app/usbcan/sja1000p.c b/embedded/app/usbcan/sja1000p.c
new file mode 100644 (file)
index 0000000..8a527ff
--- /dev/null
@@ -0,0 +1,911 @@
+/* sja1000.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Changed for PeliCan mode SJA1000 by Tomasz Motylewski (BFAD GmbH)
+ * T.Motylewski@bfad.de
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysdep.h"
+#include "./can/main.h"
+#include "./can/sja1000p.h"
+
+#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
+
+static const char *sja1000_ecc_errc_str[]={
+       "bit error",
+       "form error",
+       "stuff error",
+       "other type of error"
+};
+
+static const char *sja1000_ecc_seg_str[]={
+       "?0?",
+       "?1?",
+       "ID.28 to ID.21",
+       "start of frame",
+       "bit SRTR",
+       "bit IDE",
+       "ID.20 to ID.18",
+       "ID.17 to ID.13",
+       "CRC sequence",
+       "reserved bit 0",
+       "data field",
+       "data length code",
+       "bit RTR",
+       "reserved bit 1",
+       "ID.4 to ID.0",
+       "ID.12 to ID.5",
+       "?16?"
+       "active error flag",
+       "intermission",
+       "tolerate dominant bits",
+       "?20?",
+       "?21?",
+       "passive error flag",
+       "error delimiter",
+       "CRC delimiter",
+       "acknowledge slot",
+       "end of frame",
+       "acknowledge delimiter",
+       "overload flag",
+       "?29?",
+       "?30?",
+       "?31?"
+};
+
+#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/
+
+static int sja1000_report_error_limit_counter;
+
+static void sja1000_report_error(struct canchip_t *chip,
+                               unsigned sr, unsigned ir, unsigned ecc)
+{
+       if(sja1000_report_error_limit_counter>=100)
+               return;
+
+       CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
+               sr, ir, ecc);
+
+       sja1000_report_error_limit_counter+=10;
+
+       if(sja1000_report_error_limit_counter>=100){
+               sja1000_report_error_limit_counter+=10;
+               CANMSG("Error: too many errors, reporting disabled\n");
+               return;
+       }
+
+#ifdef CONFIG_OC_LINCAN_DETAILED_ERRORS
+       CANMSG("SR: BS=%c  ES=%c  TS=%c  RS=%c  TCS=%c TBS=%c DOS=%c RBS=%c\n",
+               sr&sjaSR_BS?'1':'0',sr&sjaSR_ES?'1':'0',
+               sr&sjaSR_TS?'1':'0',sr&sjaSR_RS?'1':'0',
+               sr&sjaSR_TCS?'1':'0',sr&sjaSR_TBS?'1':'0',
+               sr&sjaSR_DOS?'1':'0',sr&sjaSR_RBS?'1':'0');
+       CANMSG("IR: BEI=%c ALI=%c EPI=%c WUI=%c DOI=%c EI=%c  TI=%c  RI=%c\n",
+               sr&sjaIR_BEI?'1':'0',sr&sjaIR_ALI?'1':'0',
+               sr&sjaIR_EPI?'1':'0',sr&sjaIR_WUI?'1':'0',
+               sr&sjaIR_DOI?'1':'0',sr&sjaIR_EI?'1':'0',
+               sr&sjaIR_TI?'1':'0',sr&sjaIR_RI?'1':'0');
+       if((sr&sjaIR_EI) || 1){
+               CANMSG("EI: %s %s %s\n",
+                      sja1000_ecc_errc_str[(ecc&(sjaECC_ERCC1|sjaECC_ERCC0))/sjaECC_ERCC0],
+                      ecc&sjaECC_DIR?"RX":"TX",
+                      sja1000_ecc_seg_str[ecc&sjaECC_SEG_M]
+                     );
+       }
+#endif /*CONFIG_OC_LINCAN_DETAILED_ERRORS*/
+}
+
+
+/**
+ * sja1000p_enable_configuration - enable chip configuration mode
+ * @chip: pointer to chip state structure
+ */
+int sja1000p_enable_configuration(struct canchip_t *chip)
+{
+       int i=0;
+       enum sja1000_PeliCAN_MOD flags;
+
+       can_disable_irq(chip->chip_irq);
+
+       flags=can_read_reg(chip,SJAMOD);
+
+       while ((!(flags & sjaMOD_RM)) && (i<=10)) {
+               can_write_reg(chip, sjaMOD_RM, SJAMOD);
+// TODO: configurable sjaMOD_AFM (32/16 bit acceptance filter)
+// config sjaMOD_LOM (listen only)
+               udelay(100);
+               i++;
+               flags=can_read_reg(chip, SJAMOD);
+       }
+       if (i>=10) {
+               CANMSG("Reset error\n");
+               can_enable_irq(chip->chip_irq);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ * sja1000p_disable_configuration - disable chip configuration mode
+ * @chip: pointer to chip state structure
+ */
+int sja1000p_disable_configuration(struct canchip_t *chip)
+{
+       int i=0;
+       enum sja1000_PeliCAN_MOD flags;
+
+       flags=can_read_reg(chip,SJAMOD);
+
+       while ( (flags & sjaMOD_RM) && (i<=50) ) {
+// could be as long as 11*128 bit times after buss-off
+               can_write_reg(chip, 0, SJAMOD);
+// TODO: configurable sjaMOD_AFM (32/16 bit acceptance filter)
+// config sjaMOD_LOM (listen only)
+               udelay(100);
+               i++;
+               flags=can_read_reg(chip, SJAMOD);
+       }
+       if (i>=10) {
+               CANMSG("Error leaving reset status\n");
+               return -ENODEV;
+       }
+
+       can_enable_irq(chip->chip_irq);
+
+       return 0;
+}
+
+/**
+ * sja1000p_chip_config: - can chip configuration
+ * @chip: pointer to chip state structure
+ *
+ * This function configures chip and prepares it for message
+ * transmission and reception. The function resets chip,
+ * resets mask for acceptance of all messages by call to
+ * sja1000p_extended_mask() function and then
+ * computes and sets baudrate with use of function sja1000p_baud_rate().
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_chip_config(struct canchip_t *chip)
+{
+       int i;
+       unsigned char n, r;
+
+       if (sja1000p_enable_configuration(chip))
+               return -ENODEV;
+
+       /* Set mode, clock out, comparator */
+       can_write_reg(chip,sjaCDR_PELICAN|chip->sja_cdr_reg,SJACDR);
+
+       /* Ensure, that interrupts are disabled even on the chip level now */
+       can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
+
+       /* Set driver output configuration */
+       can_write_reg(chip,chip->sja_ocr_reg,SJAOCR);
+
+       /* Simple check for chip presence */
+       for (i=0, n=0x5a; i<8; i++, n+=0xf) {
+               can_write_reg(chip,n,SJAACR0+i);
+       }
+       for (i=0, n=0x5a; i<8; i++, n+=0xf) {
+               r = n^can_read_reg(chip,SJAACR0+i);
+               if (r) {
+                       CANMSG("sja1000p_chip_config: chip connection broken,"
+                               " readback differ 0x%02x\n", r);
+                       return -ENODEV;
+               }
+       }
+
+
+       if (sja1000p_extended_mask(chip,0x00000000, 0xffffffff))
+               return -ENODEV;
+
+       if (!chip->baudrate)
+               chip->baudrate=1000000;
+       if (sja1000p_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
+               return -ENODEV;
+
+       /* Enable hardware interrupts */
+       can_write_reg(chip, sjaENABLE_INTERRUPTS, SJAIER);
+
+       sja1000p_disable_configuration(chip);
+
+       return 0;
+}
+
+/**
+ * sja1000p_extended_mask: - setup of extended mask for message filtering
+ * @chip: pointer to chip state structure
+ * @code: can message acceptance code
+ * @mask: can message acceptance mask
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_extended_mask(struct canchip_t *chip, unsigned long code, unsigned  long mask)
+{
+       int i;
+
+       if (sja1000p_enable_configuration(chip))
+               return -ENODEV;
+
+// LSB to +3, MSB to +0
+       for(i=SJA_PeliCAN_AC_LEN; --i>=0;) {
+               can_write_reg(chip,code&0xff,SJAACR0+i);
+               can_write_reg(chip,mask&0xff,SJAAMR0+i);
+               code >>= 8;
+               mask >>= 8;
+       }
+
+       DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
+       DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
+
+       sja1000p_disable_configuration(chip);
+
+       return 0;
+}
+
+/**
+ * sja1000p_baud_rate: - set communication parameters.
+ * @chip: pointer to chip state structure
+ * @rate: baud rate in Hz
+ * @clock: frequency of sja1000 clock in Hz (ISA osc is 14318000)
+ * @sjw: synchronization jump width (0-3) prescaled clock cycles
+ * @sampl_pt: sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio
+ * @flags: fields %BTR1_SAM, %OCMODE, %OCPOL, %OCTP, %OCTN, %CLK_OFF, %CBP
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
+                                                       int sampl_pt, int flags)
+{
+       int best_error = 1000000000, error;
+       int best_tseg=0, best_brp=0, best_rate=0, brp=0;
+       int tseg=0, tseg1=0, tseg2=0;
+
+       if (sja1000p_enable_configuration(chip))
+               return -ENODEV;
+
+       clock /=2;
+
+       /* tseg even = round down, odd = round up */
+       for (tseg=(0+0+2)*2; tseg<=(sjaMAX_TSEG2+sjaMAX_TSEG1+2)*2+1; tseg++) {
+               brp = clock/((1+tseg/2)*rate)+tseg%2;
+               if (brp == 0 || brp > 64)
+                       continue;
+               error = rate - clock/(brp*(1+tseg/2));
+               if (error < 0)
+                       error = -error;
+               if (error <= best_error) {
+                       best_error = error;
+                       best_tseg = tseg/2;
+                       best_brp = brp-1;
+                       best_rate = clock/(brp*(1+tseg/2));
+               }
+       }
+       if (best_error && (rate/best_error < 10)) {
+               CANMSG("baud rate %d is not possible with %d Hz clock\n",
+                                                               rate, 2*clock);
+               CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n",
+                               best_rate, best_brp, best_tseg, tseg1, tseg2);
+               return -EINVAL;
+       }
+       tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100;
+       if (tseg2 < 0)
+               tseg2 = 0;
+       if (tseg2 > sjaMAX_TSEG2)
+               tseg2 = sjaMAX_TSEG2;
+       tseg1 = best_tseg-tseg2-2;
+       if (tseg1>sjaMAX_TSEG1) {
+               tseg1 = sjaMAX_TSEG1;
+               tseg2 = best_tseg-tseg1-2;
+       }
+
+       DEBUGMSG("Setting %d bps.\n", best_rate);
+       DEBUGMSG("brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n",
+                                       best_brp, best_tseg, tseg1, tseg2,
+                                       (100*(best_tseg-tseg2)/(best_tseg+1)));
+
+
+       can_write_reg(chip, sjw<<6 | best_brp, SJABTR0);
+       can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | (tseg2<<4)
+                                       | tseg1, SJABTR1);
+
+       sja1000p_disable_configuration(chip);
+
+       return 0;
+}
+
+/**
+ * sja1000p_read: - reads and distributes one or more received messages
+ * @chip: pointer to chip state structure
+ * @obj: pinter to CAN message queue information
+ *
+ * File: src/sja1000p.c
+ */
+void sja1000p_read(struct canchip_t *chip, struct msgobj_t *obj) {
+       int i, flags, len, datastart;
+       do {
+               flags = can_read_reg(chip,SJAFRM);
+               if(flags&sjaFRM_FF) {
+                       obj->rx_msg.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 {
+                       obj->rx_msg.id =
+                               (can_read_reg(chip,SJAID0)<<3) +
+                               (can_read_reg(chip,SJAID1)>>5);
+                       datastart = SJADATS;
+               }
+               obj->rx_msg.flags =
+                       ((flags & sjaFRM_RTR) ? MSG_RTR : 0) |
+                       ((flags & sjaFRM_FF) ? MSG_EXT : 0);
+               len = flags & sjaFRM_DLC_M;
+               obj->rx_msg.length = len;
+               if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+               for(i=0; i< len; i++) {
+                       obj->rx_msg.data[i]=can_read_reg(chip,datastart+i);
+               }
+
+               /* fill CAN message timestamp */
+               can_filltimestamp(&obj->rx_msg.timestamp);
+
+               canque_filter_msg2edges(obj->qends, &obj->rx_msg);
+
+               can_write_reg(chip, sjaCMR_RRB, SJACMR);
+
+       } while (can_read_reg(chip, SJASR) & sjaSR_RBS);
+}
+
+/**
+ * sja1000p_pre_read_config: - prepares message object for message reception
+ * @chip: pointer to chip state structure
+ * @obj: pointer to message object state structure
+ *
+ * Return Value: negative value reports error.
+ *     Positive value indicates immediate reception of message.
+ * File: src/sja1000p.c
+ */
+int sja1000p_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       int status;
+       status=can_read_reg(chip,SJASR);
+
+       if(status  & sjaSR_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&sjaSR_RBS)) {
+               return 0;
+       }
+
+       can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER); //disable interrupts for a moment
+       sja1000p_read(chip, obj);
+       can_write_reg(chip, sjaENABLE_INTERRUPTS, SJAIER); //enable interrupts
+       return 1;
+}
+
+#define MAX_TRANSMIT_WAIT_LOOPS 10
+/**
+ * sja1000p_pre_write_config: - prepares message object for message transmission
+ * @chip: pointer to chip state structure
+ * @obj: pointer to message object state structure
+ * @msg: pointer to CAN message
+ *
+ * This function prepares selected message object for future initiation
+ * of message transmission by sja1000p_send_msg() function.
+ * The CAN message data and message ID are transfered from @msg slot
+ * into chip buffer in this function.
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
+                                                       struct canmsg_t *msg)
+{
+       int i=0;
+       unsigned int id;
+       int status;
+       int len;
+
+       /* Wait until Transmit Buffer Status is released */
+       while ( !((status=can_read_reg(chip, SJASR)) & sjaSR_TBS) &&
+                                               i++<MAX_TRANSMIT_WAIT_LOOPS) {
+               udelay(i);
+       }
+
+       if(status & sjaSR_BS) {
+               /* Try to recover from error condition */
+               DEBUGMSG("sja1000p_pre_write_config bus-off recover 0x%x\n",status);
+               sja1000p_enable_configuration(chip);
+               can_write_reg(chip, 0, SJARXERR);
+               can_write_reg(chip, 0, SJATXERR1);
+               can_read_reg(chip, SJAECC);
+               sja1000p_disable_configuration(chip);
+       }
+       if (!(can_read_reg(chip, SJASR) & sjaSR_TBS)) {
+               CANMSG("Transmit timed out, cancelling\n");
+// here we should check if there is no write/select waiting for this
+// transmit. If so, set error ret and wake up.
+// CHECKME: if we do not disable sjaIER_TIE (TX IRQ) here we get interrupt
+// immediately
+               can_write_reg(chip, sjaCMR_AT, SJACMR);
+               i=0;
+               while ( !(can_read_reg(chip, SJASR) & sjaSR_TBS) &&
+                                               i++<MAX_TRANSMIT_WAIT_LOOPS) {
+                       udelay(i);
+               }
+               if (!(can_read_reg(chip, SJASR) & sjaSR_TBS)) {
+                       CANMSG("Could not cancel, please reset\n");
+                       return -EIO;
+               }
+       }
+       len = msg->length;
+       if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+       /* len &= sjaFRM_DLC_M; ensured by above condition already */
+       can_write_reg(chip, ((msg->flags&MSG_EXT)?sjaFRM_FF:0) |
+               ((msg->flags & MSG_RTR) ? sjaFRM_RTR : 0) | len, SJAFRM);
+       if(msg->flags&MSG_EXT) {
+               id=msg->id<<3;
+               can_write_reg(chip, id & 0xff, SJAID3);
+               id >>= 8;
+               can_write_reg(chip, id & 0xff, SJAID2);
+               id >>= 8;
+               can_write_reg(chip, id & 0xff, SJAID1);
+               id >>= 8;
+               can_write_reg(chip, id, SJAID0);
+               for(i=0; i < len; i++) {
+                       can_write_reg(chip, msg->data[i], SJADATE+i);
+               }
+       } else {
+               id=msg->id<<5;
+               can_write_reg(chip, (id >> 8) & 0xff, SJAID0);
+               can_write_reg(chip, id & 0xff, SJAID1);
+               for(i=0; i < len; i++) {
+                       can_write_reg(chip, msg->data[i], SJADATS+i);
+               }
+       }
+       return 0;
+}
+
+/**
+ * sja1000p_send_msg: - initiate message transmission
+ * @chip: pointer to chip state structure
+ * @obj: pointer to message object state structure
+ * @msg: pointer to CAN message
+ *
+ * This function is called after sja1000p_pre_write_config() function,
+ * which prepares data in chip buffer.
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
+                                                       struct canmsg_t *msg)
+{
+       can_write_reg(chip, sjaCMR_TR, SJACMR);
+
+       return 0;
+}
+
+/**
+ * sja1000p_check_tx_stat: - checks state of transmission engine
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ *     Positive return value indicates transmission under way status.
+ *     Zero value indicates finishing of all issued transmission requests.
+ * File: src/sja1000p.c
+ */
+int sja1000p_check_tx_stat(struct canchip_t *chip)
+{
+       if (can_read_reg(chip,SJASR) & sjaSR_TCS)
+               return 0;
+       else
+               return 1;
+}
+
+/**
+ * sja1000p_set_btregs: -  configures bitrate registers
+ * @chip: pointer to chip state structure
+ * @btr0: bitrate register 0
+ * @btr1: bitrate register 1
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_set_btregs(struct canchip_t *chip, unsigned short btr0,
+                                                       unsigned short btr1)
+{
+       if (sja1000p_enable_configuration(chip))
+               return -ENODEV;
+
+       can_write_reg(chip, btr0, SJABTR0);
+       can_write_reg(chip, btr1, SJABTR1);
+
+       sja1000p_disable_configuration(chip);
+
+       return 0;
+}
+
+/**
+ * sja1000p_start_chip: -  starts chip message processing
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_start_chip(struct canchip_t *chip)
+{
+       enum sja1000_PeliCAN_MOD flags;
+
+       flags = can_read_reg(chip, SJAMOD) & (sjaMOD_LOM|sjaMOD_STM|sjaMOD_AFM|sjaMOD_SM);
+       can_write_reg(chip, flags, SJAMOD);
+
+       sja1000_report_error_limit_counter=0;
+
+       return 0;
+}
+
+/**
+ * sja1000p_stop_chip: -  stops chip message processing
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_stop_chip(struct canchip_t *chip)
+{
+       enum sja1000_PeliCAN_MOD flags;
+
+       flags = can_read_reg(chip, SJAMOD) & (sjaMOD_LOM|sjaMOD_STM|sjaMOD_AFM|sjaMOD_SM);
+       can_write_reg(chip, flags|sjaMOD_RM, SJAMOD);
+
+       return 0;
+}
+
+/**
+ * sja1000p_attach_to_chip: - attaches to the chip, setups registers and state
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_attach_to_chip(struct canchip_t *chip)
+{
+       return 0;
+}
+
+/**
+ * sja1000p_release_chip: - called before chip structure removal if %CHIP_ATTACHED is set
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_release_chip(struct canchip_t *chip)
+{
+       sja1000p_stop_chip(chip);
+       can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
+
+       return 0;
+}
+
+/**
+ * sja1000p_remote_request: - configures message object and asks for RTR message
+ * @chip: pointer to chip state structure
+ * @obj: pointer to message object structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_remote_request(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       CANMSG("sja1000p_remote_request not implemented\n");
+       return -ENOSYS;
+}
+
+/**
+ * sja1000p_standard_mask: - setup of mask for message filtering
+ * @chip: pointer to chip state structure
+ * @code: can message acceptance code
+ * @mask: can message acceptance mask
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_standard_mask(struct canchip_t *chip, unsigned short code,
+               unsigned short mask)
+{
+       CANMSG("sja1000p_standard_mask not implemented\n");
+       return -ENOSYS;
+}
+
+/**
+ * sja1000p_clear_objects: - clears state of all message object residing in chip
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_clear_objects(struct canchip_t *chip)
+{
+       CANMSG("sja1000p_clear_objects not implemented\n");
+       return -ENOSYS;
+}
+
+/**
+ * sja1000p_config_irqs: - tunes chip hardware interrupt delivery
+ * @chip: pointer to chip state structure
+ * @irqs: requested chip IRQ configuration
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_config_irqs(struct canchip_t *chip, short irqs)
+{
+       CANMSG("sja1000p_config_irqs not implemented\n");
+       return -ENOSYS;
+}
+
+/**
+ * sja1000p_irq_write_handler: - part of ISR code responsible for transmit events
+ * @chip: pointer to chip state structure
+ * @obj: pointer to attached queue description
+ *
+ * The main purpose of this function is to read message from attached queues
+ * and transfer message contents into CAN controller chip.
+ * This subroutine is called by
+ * sja1000p_irq_write_handler() for transmit events.
+ * File: src/sja1000p.c
+ */
+void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       int cmd;
+
+       if(obj->tx_slot){
+               /* Do local transmitted message distribution if enabled */
+               if (processlocal){
+                       /* fill CAN message timestamp */
+                       can_filltimestamp(&obj->tx_slot->msg.timestamp);
+
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+       }
+
+       can_msgobj_clear_fl(obj,TX_PENDING);
+       cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+       if(cmd<0)
+               return;
+       can_msgobj_set_fl(obj,TX_PENDING);
+
+       if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) {
+               obj->ret = -1;
+               canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP);
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+               return;
+       }
+       if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) {
+               obj->ret = -1;
+               canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+               return;
+       }
+
+}
+
+#define MAX_RETR 10
+
+/**
+ * sja1000p_irq_handler: - interrupt service routine
+ * @irq: interrupt vector number, this value is system specific
+ * @chip: pointer to chip state structure
+ *
+ * Interrupt handler is activated when state of CAN controller chip changes,
+ * there is message to be read or there is more space for new messages or
+ * error occurs. The receive events results in reading of the message from
+ * CAN controller chip and distribution of message through attached
+ * message queues.
+ * File: src/sja1000p.c
+ */
+int sja1000p_irq_handler(int irq, struct canchip_t *chip)
+{
+       int irq_register, status, error_code;
+       struct msgobj_t *obj=chip->msgobj[0];
+       int loop_cnt=CHIP_MAX_IRQLOOP;
+
+       irq_register=can_read_reg(chip,SJAIR);
+//     DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);
+//     DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n",
+//                                     can_read_reg(chip,SJASR));
+
+       if ((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) == 0)
+               return CANCHIP_IRQ_NONE;
+
+       if(!(chip->flags&CHIP_CONFIGURED)) {
+               CANMSG("sja1000p_irq_handler: called for non-configured device, irq_register 0x%02x\n", irq_register);
+               return CANCHIP_IRQ_NONE;
+       }
+
+       status=can_read_reg(chip,SJASR);
+
+       do {
+
+               if(!loop_cnt--) {
+                       CANMSG("sja1000p_irq_handler IRQ %d stuck\n",irq);
+                       return CANCHIP_IRQ_STUCK;
+               }
+
+               /* (irq_register & sjaIR_RI) */
+               /*      old variant using SJAIR, collides with intended use with irq_accept */
+               if (status & sjaSR_RBS) {
+                       DEBUGMSG("sja1000_irq_handler: RI or RBS\n");
+                       sja1000p_read(chip,obj);
+                       obj->ret = 0;
+               }
+
+               /* (irq_register & sjaIR_TI) */
+               /*      old variant using SJAIR, collides with intended use with irq_accept */
+               if (((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING))||
+                   (can_msgobj_test_fl(obj,TX_REQUEST))) {
+                       DEBUGMSG("sja1000_irq_handler: TI or TX_PENDING and TBS\n");
+                       obj->ret = 0;
+                       can_msgobj_set_fl(obj,TX_REQUEST);
+                       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+                               can_msgobj_clear_fl(obj,TX_REQUEST);
+
+                               if (can_read_reg(chip, SJASR) & sjaSR_TBS)
+                                       sja1000p_irq_write_handler(chip, obj);
+
+                               can_msgobj_clear_fl(obj,TX_LOCK);
+                               if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
+                               DEBUGMSG("TX looping in sja1000_irq_handler\n");
+                       }
+               }
+               if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) {
+                       // Some error happened
+                       error_code=can_read_reg(chip,SJAECC);
+                       sja1000_report_error(chip, 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
+                       obj->ret=-1;
+
+                       if(error_code == 0xd9) {
+                               obj->ret= -ENXIO;
+                               /* no such device or address - no ACK received */
+                       }
+                       if(obj->tx_retry_cnt++>MAX_RETR) {
+                               can_write_reg(chip, sjaCMR_AT, SJACMR); // cancel any transmition
+                               obj->tx_retry_cnt = 0;
+                       }
+                       if(status&sjaSR_BS) {
+                               CANMSG("bus-off, resetting sja1000p\n");
+                               can_write_reg(chip, 0, SJAMOD);
+                       }
+
+                       if(obj->tx_slot){
+                               canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS);
+                               /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+                               obj->tx_slot=NULL;*/
+                       }
+
+               } else {
+                       if(sja1000_report_error_limit_counter)
+                               sja1000_report_error_limit_counter--;
+                       obj->tx_retry_cnt=0;
+               }
+
+               irq_register=can_read_reg(chip,SJAIR);
+
+               status=can_read_reg(chip,SJASR);
+
+               if(((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) ||
+                  (irq_register & sjaIR_TI))
+                        can_msgobj_set_fl(obj,TX_REQUEST);
+
+       } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_RI)) ||
+               (can_msgobj_test_fl(obj,TX_REQUEST) && !can_msgobj_test_fl(obj,TX_LOCK)) ||
+               (status & sjaSR_RBS));
+
+       return CANCHIP_IRQ_HANDLED;
+}
+
+/**
+ * sja1000p_wakeup_tx: - wakeups TX processing
+ * @chip: pointer to chip state structure
+ * @obj: pointer to message object structure
+ *
+ * Function is responsible for initiating message transmition.
+ * It is responsible for clearing of object TX_REQUEST flag
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
+{
+
+       can_preempt_disable();
+
+       can_msgobj_set_fl(obj,TX_PENDING);
+       can_msgobj_set_fl(obj,TX_REQUEST);
+       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+               can_msgobj_clear_fl(obj,TX_REQUEST);
+
+               if (can_read_reg(chip, SJASR) & sjaSR_TBS){
+                       obj->tx_retry_cnt=0;
+                       sja1000p_irq_write_handler(chip, obj);
+               }
+
+               can_msgobj_clear_fl(obj,TX_LOCK);
+               if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
+               DEBUGMSG("TX looping in sja1000p_wakeup_tx\n");
+       }
+
+       can_preempt_enable();
+       return 0;
+}
+
+int sja1000p_register(struct chipspecops_t *chipspecops)
+{
+       CANMSG("initializing sja1000p chip operations\n");
+       chipspecops->chip_config=sja1000p_chip_config;
+       chipspecops->baud_rate=sja1000p_baud_rate;
+       chipspecops->standard_mask=sja1000p_standard_mask;
+       chipspecops->extended_mask=sja1000p_extended_mask;
+       chipspecops->message15_mask=sja1000p_extended_mask;
+       chipspecops->clear_objects=sja1000p_clear_objects;
+       chipspecops->config_irqs=sja1000p_config_irqs;
+       chipspecops->pre_read_config=sja1000p_pre_read_config;
+       chipspecops->pre_write_config=sja1000p_pre_write_config;
+       chipspecops->send_msg=sja1000p_send_msg;
+       chipspecops->check_tx_stat=sja1000p_check_tx_stat;
+       chipspecops->wakeup_tx=sja1000p_wakeup_tx;
+       chipspecops->remote_request=sja1000p_remote_request;
+       chipspecops->enable_configuration=sja1000p_enable_configuration;
+       chipspecops->disable_configuration=sja1000p_disable_configuration;
+       chipspecops->attach_to_chip=sja1000p_attach_to_chip;
+       chipspecops->release_chip=sja1000p_release_chip;
+       chipspecops->set_btregs=sja1000p_set_btregs;
+       chipspecops->start_chip=sja1000p_start_chip;
+       chipspecops->stop_chip=sja1000p_stop_chip;
+       chipspecops->irq_handler=sja1000p_irq_handler;
+       chipspecops->irq_accept=NULL;
+       return 0;
+}
+
+/**
+ * sja1000p_fill_chipspecops - fills chip specific operations
+ * @chip: pointer to chip representation structure
+ *
+ * The function fills chip specific operations for sja1000 (PeliCAN) chip.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int sja1000p_fill_chipspecops(struct canchip_t *chip)
+{
+       chip->chip_type="sja1000p";
+       chip->max_objects=1;
+       sja1000p_register(chip->chipspecops);
+       return 0;
+}
diff --git a/embedded/app/usbcan/ul_usb1.c b/embedded/app/usbcan/ul_usb1.c
new file mode 100644 (file)
index 0000000..abb1626
--- /dev/null
@@ -0,0 +1,539 @@
+/* ul_usb1.c
+ * Linux CAN-bus device driver.
+ * Written by Jan Kriz email:johen@post.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.3  17 Jun 2004
+ *
+ * Based on
+ *     USB Skeleton driver - 2.2
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2.
+ *
+ * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
+ * but has been rewritten to be easier to read and use.
+ *
+ */
+
+#include "./can/can.h"
+#include "./can/can_sysdep.h"
+#include "./can/main.h"
+#include "./can/devcommon.h"
+#include "./can/setup.h"
+// #include "./can/finish.h"
+#include "./can/i82527.h"
+//#include "../include/sja1000.h"
+#include "./can/sja1000p.h"
+
+#include "./can/errno.h"
+
+#include "./can/ul_usb1.h"
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE    192
+
+#define CAN_OP_MASK 0x80
+#define CAN_OP_READ 0x80
+#define CAN_OP_WRITE 0x00
+
+
+       /* our private defines. if this grows any larger, use your own .h file */
+#define MAX_TRANSFER           (PAGE_SIZE - 512)
+/* MAX_TRANSFER is chosen so that the VM is not stressed by
+   allocations > PAGE_SIZE and the number of packets in a page
+   is an integer 512 is the largest possible packet on EHCI */
+#define WRITES_IN_FLIGHT       8
+/* arbitrarily chosen */
+
+/* Define these values to match your devices */
+#define USB_SKEL_VENDOR_ID     0xDEAD
+#define USB_SKEL_PRODUCT_ID    0x1001
+
+/* table of devices that work with this driver */
+// static struct usb_device_id ul_usb1_table [] = {
+//     { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+//     { }                                     /* Terminating entry */
+// };
+// MODULE_DEVICE_TABLE(usb, ul_usb1_table);
+
+// extern struct file_operations can_fops;
+
+// struct ul_usb1_combo {
+//     struct usb_ul_usb1 * dev;
+//     struct urb * urb;
+// };
+
+/*
+ * 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
+
+/** ul_usb1_request_io
+ * ul_usb1_request_io: - reserve io or memory range for can board
+ * @candev: pointer to candevice/board which asks for io. Field @io_addr
+ *     of @candev is used in most cases to define start of the range
+ *
+ * The function ul_usb1_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/ul_usb1.c
+ */
+int ul_usb1_request_io(struct candevice_t *candev)
+{
+//     ((struct usb_ul_usb1*)candev->sysdevptr.anydev)->candev=candev;
+       return 0;
+}
+
+/** ul_usb1_release_io
+ * ul_usb1_release_io - free reserved io memory range
+ * @candev: pointer to candevice/board which releases io
+ *
+ * The function ul_usb1_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/ul_usb1.c
+ */
+int ul_usb1_release_io(struct candevice_t *candev)
+{
+/*     struct usb_ul_usb1 *dev;
+       if (candev->sysdevptr.anydev){
+               dev=(struct usb_ul_usb1*) candev->sysdevptr.anydev;
+               usb_put_dev(dev->udev);
+               usb_kill_urb(dev->irq);
+               usb_free_urb(dev->irq);
+               kfree(dev->bulk_in_buffer);
+               kfree(dev->int_in_buffer);
+               if (dev->candev){
+                       dev->candev->sysdevptr.anydev=NULL;
+                       //cleanup_usbdev(dev->candev);
+               }
+               kfree(dev);
+       }*/
+       return 0;
+}
+
+/** ul_usb1_reset
+ * ul_usb1_reset - hardware reset routine
+ * @candev: Pointer to candevice/board structure
+ *
+ * The function ul_usb1_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/ul_usb1.c
+ */
+int ul_usb1_reset(struct candevice_t *candev)
+{
+       return 0;
+}
+
+#define RESET_ADDR 0x0
+#define NR_82527 0
+#define NR_SJA1000 1
+
+/** ul_usb1_init_hw_data
+ * ul_usb1_init_hw_data - Initialize hardware cards
+ * @candev: Pointer to candevice/board structure
+ *
+ * The function ul_usb1_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 %CANDEV_PROGRAMMABLE_IRQ to indicate that
+ * the hardware uses programmable interrupts.
+ * Return Value: The function always returns zero
+ * File: src/ul_usb1.c
+ */
+int ul_usb1_init_hw_data(struct candevice_t *candev)
+{
+       candev->res_addr=RESET_ADDR;
+       candev->nr_82527_chips=NR_82527;
+       candev->nr_sja1000_chips=NR_SJA1000;
+       candev->nr_all_chips=NR_82527+NR_SJA1000;
+       candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
+
+       return 0;
+}
+
+/** ul_usb1_init_chip_data
+ * ul_usb1_init_chip_data - Initialize chips
+ * @candev: Pointer to candevice/board structure
+ * @chipnr: Number of the CAN chip on the hardware card
+ *
+ * The function ul_usb1_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:
+ * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN
+ * The entry @sja_ocr_reg holds hardware specific options for the Output Control
+ * register. Options defined in the %sja1000.h file:
+ * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK,
+ * %sjaOCR_TX0_LH, %sjaOCR_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/ul_usb1.c
+ */
+int ul_usb1_init_chip_data(struct candevice_t *candev, int chipnr)
+{
+       /*i82527_fill_chipspecops(candev->chip[chipnr]);*/
+       /*sja1000_fill_chipspecops(candev->chip[chipnr]);*/
+       sja1000p_fill_chipspecops(candev->chip[chipnr]);
+
+       candev->chip[chipnr]->flags|= CHIP_IRQ_CUSTOM;
+
+       candev->chip[chipnr]->chip_base_addr=0;
+       candev->chip[chipnr]->clock = 24000000;
+       candev->chip[chipnr]->int_cpu_reg = iCPU_DSC;
+       candev->chip[chipnr]->int_clk_reg = iCLK_SL1;
+       candev->chip[chipnr]->int_bus_reg = iBUS_CBY;
+       candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
+       candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL |
+                                                               sjaOCR_TX0_LH;
+
+       candev->chip[chipnr]->chip_data=(void *)malloc(sizeof(struct ul_usb1_chip_data));
+       if (candev->chip[chipnr]->chip_data==NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/** ul_usb1_init_obj_data
+ * ul_usb1_init_obj_data - Initialize message buffers
+ * @chip: Pointer to chip specific structure
+ * @objnr: Number of the message buffer
+ *
+ * The function ul_usb1_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/ul_usb1.c
+ */
+int ul_usb1_init_obj_data(struct canchip_t *chip, int objnr)
+{
+       chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
+
+       return 0;
+}
+
+/** ul_usb1_program_irq
+ * ul_usb1_program_irq - program interrupts
+ * @candev: Pointer to candevice/board structure
+ *
+ * The function ul_usb1_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 %CANDEV_PROGRAMMABLE_IRQ and
+ * leave this function unedited. Again this function is hardware specific so
+ * there's no example code.
+ * Return value: The function returns zero on success or %-ENODEV on failure
+ * File: src/ul_usb1.c
+ */
+int ul_usb1_program_irq(struct candevice_t *candev)
+{
+       return 0;
+}
+
+/** ul_usb1_write_register
+ * ul_usb1_write_register - Low level write register routine
+ * @data: data to be written
+ * @address: memory address to write to
+ *
+ * The function ul_usb1_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/ul_usb1.c
+ */
+void ul_usb1_write_register(unsigned data, unsigned long address)
+{
+       can_write((uint8_t)(address & 0xFF), (uint8_t *)&data);
+}
+
+/** ul_usb1_read_register
+ * ul_usb1_read_register - Low level read register routine
+ * @address: memory address to read from
+ *
+ * The function ul_usb1_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/ul_usb1.c
+ */
+unsigned ul_usb1_read_register(unsigned long address)
+{
+       uint8_t data;
+       can_read((uint8_t)(address & 0xFF), (uint8_t *)&data);
+       return data;
+}
+
+/* !!! Don't change this function !!! */
+int ul_usb1_register(struct hwspecops_t *hwspecops)
+{
+       hwspecops->request_io = ul_usb1_request_io;
+       hwspecops->release_io = ul_usb1_release_io;
+       hwspecops->reset = ul_usb1_reset;
+       hwspecops->init_hw_data = ul_usb1_init_hw_data;
+       hwspecops->init_chip_data = ul_usb1_init_chip_data;
+       hwspecops->init_obj_data = ul_usb1_init_obj_data;
+       hwspecops->write_register = ul_usb1_write_register;
+       hwspecops->read_register = ul_usb1_read_register;
+       hwspecops->program_irq = ul_usb1_program_irq;
+       return 0;
+}
+
+
+
+
+/* --------------------------------------------------------------------------------------------------- */
+
+
+// static void ul_usb1_irq(struct urb *urb)
+// {
+//     struct usb_ul_usb1 *dev = urb->context;
+//     struct ul_usb1_combo devc;
+//     int retval;
+//
+//     CANMSG("Interrupt poll\n");
+//
+//     switch (urb->status) {
+//     case 0:
+//             /* success */
+//             break;
+//     case -ECONNRESET:
+//     case -ENOENT:
+//     case -ESHUTDOWN:
+//             /* this urb is terminated, clean up */
+//             CANMSG("%s - urb shutting down with status: %d\n", __FUNCTION__, urb->status);
+//             return;
+//     default:
+//             CANMSG("%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
+//             goto exit;
+//     }
+//
+//     devc.dev = dev;
+//     devc.urb = urb;
+//
+//     dev->candev->chip[0]->chipspecops->irq_handler(0,dev->candev->chip[0]);
+//     CANMSG("Interrupt caught\n");
+//
+//  exit:
+//     retval = usb_submit_urb (urb, GFP_ATOMIC);
+//     if (retval)
+//             CANMSG("%s - usb_submit_urb failed with result %d\n",
+//                  __FUNCTION__, retval);
+// }
+
+// static void ul_usb1_delete(struct usb_ul_usb1 *dev)
+// {
+//     usb_put_dev(dev->udev);
+//     usb_kill_urb(dev->irq);
+//     usb_free_urb(dev->irq);
+//     kfree(dev->bulk_in_buffer);
+//     kfree(dev->int_in_buffer);
+//     if (dev->candev){
+//             dev->candev->sysdevptr.anydev=NULL;
+//             cleanup_usbdev(dev->candev);
+//     }
+//     kfree(dev);
+// }
+
+// static int ul_usb1_probe(struct usb_interface *interface, const struct usb_device_id *id)
+// {
+//     struct usb_ul_usb1 *dev;
+//     struct usb_host_interface *iface_desc;
+//     struct usb_endpoint_descriptor *endpoint;
+//     struct candevice_t *candev;
+//     size_t buffer_size;
+//     int i;
+//     int retval = -ENOMEM;
+//
+//     /* allocate memory for our device state and initialize it */
+//     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+//     if (!dev) {
+//             err("Out of memory");
+//             goto error;
+//     }
+//     sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
+//     mutex_init(&dev->io_mutex);
+//     spin_lock_init(&dev->err_lock);
+//     init_usb_anchor(&dev->submitted);
+//
+// //  dev->udev = usb_get_dev(interface_to_usbdev(interface));
+//     dev->udev = interface_to_usbdev(interface);
+//     dev->interface = interface;
+//
+//     /* set up the endpoint information */
+//     /* use only the first bulk-in and bulk-out endpoints */
+//     iface_desc = interface->cur_altsetting;
+//     for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+//             endpoint = &iface_desc->endpoint[i].desc;
+//
+//             if (!dev->bulk_in_endpointAddr &&
+//                 usb_endpoint_is_bulk_in(endpoint)) {
+//                     /* we found a bulk in endpoint */
+//                     buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+//                     dev->bulk_in_size = buffer_size;
+//                     dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+//                     dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+//                     if (!dev->bulk_in_buffer) {
+//                             err("Could not allocate bulk_in_buffer");
+//                             goto error;
+//                     }
+//             }
+//
+//             if (!dev->bulk_out_endpointAddr &&
+//                 usb_endpoint_is_bulk_out(endpoint)) {
+//                     /* we found a bulk out endpoint */
+//                             dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+//             }
+//
+//             if (!dev->int_in_endpointAddr &&
+//                 usb_endpoint_is_int_in(endpoint)) {
+//                     /* we found an interrupt in endpoint */
+//                     buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+//                     dev->int_in_size = buffer_size;
+//                     dev->int_in_endpointAddr = endpoint->bEndpointAddress;
+//                     dev->int_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+//                     dev->int_in_interval = endpoint->bInterval;
+//                     if (!dev->int_in_buffer) {
+//                             err("Could not allocate int_in_buffer");
+//                             goto error;
+//                     }
+//             }
+//     }
+//     if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr && dev->int_in_endpointAddr)) {
+//             err("Could not find all bulk-in, bulk-out and interrupt endpoints");
+//             goto error;
+//     }
+//
+//     /* save our data pointer in this interface device */
+//     usb_set_intfdata(interface, dev);
+//
+//     if (main_init_done==1)
+//             register_usbdev("ul_usb1",(void *) dev);
+//     else {
+//             mutex_lock(&usbdev_reg_mutex);
+//             if (main_init_done==1)
+//                     register_usbdev("ul_usb1",(void *) dev);
+//             else {
+//                     for (i=0;i<MAX_HW_CARDS;i++){
+//                             if (usbregq[i]==NULL){
+//                                     usbregq[i]=(struct usbdev_reg_query *)can_checked_malloc(sizeof(struct usbdev_reg_query));
+//                                     if (!usbregq[i]){
+//                                             CANMSG("Error allocating usbdev_reg_query");
+//                                             mutex_unlock(&usbdev_reg_mutex);
+//                                             goto error;
+//                                     }
+//                                     sprintf (usbregq[i]->hwname,"ul_usb1");
+//                                     usbregq[i]->anydev=(void *) dev;
+//                                     break;
+//                             }
+//                     }
+//                     if (i==MAX_HW_CARDS){
+//                             CANMSG("No free space to register new card");
+//                             mutex_unlock(&usbdev_reg_mutex);
+//                             goto error;
+//                     }
+//             }
+//             mutex_unlock(&usbdev_reg_mutex);
+//     }
+//
+//     dev->irq = usb_alloc_urb(0, GFP_KERNEL);
+//     if (!dev->irq){
+//             CANMSG("Error allocating usb urb\n");
+//             goto error;
+//     }
+//     dev->irq->dev = dev->udev;
+//     usb_fill_int_urb(dev->irq, dev->udev,
+//                      usb_rcvintpipe(dev->udev, dev->int_in_endpointAddr),
+//                      dev->int_in_buffer, dev->int_in_size,
+//                      ul_usb1_irq, dev, dev->int_in_interval);
+// /*  usb_fill_bulk_urb(dev->irq, dev->udev,
+//                      usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+//                      dev->int_in_buffer, dev->int_in_size,
+//                      ul_usb1_irq, dev);*/
+//
+// /*  dev->irq->transfer_dma = wacom->data_dma;
+//     dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;*/
+//     retval=usb_submit_urb(dev->irq, GFP_KERNEL);
+//     if (retval){
+//             CANMSG("INT URB %d\n",retval);
+//             return -EIO;
+//     }else
+//             CANMSG("INT URB SUCCCESS\n");
+//
+//     /* let the user know what node this device is now attached to */
+//     info("USB Skeleton device now attached");
+//     return 0;
+//
+// error:
+//             ul_usb1_delete(dev);
+//     return retval;
+// }
+
+// static void ul_usb1_disconnect(struct usb_interface *interface)
+// {
+//     struct usb_ul_usb1 *dev;
+//     int minor = interface->minor;
+//
+//     dev = usb_get_intfdata(interface);
+//     usb_set_intfdata(interface, NULL);
+//
+//     /* prevent more I/O from starting */
+//     mutex_lock(&dev->io_mutex);
+//     dev->interface = NULL;
+//     mutex_unlock(&dev->io_mutex);
+//
+//     //usb_kill_anchored_urbs(&dev->submitted);
+//
+//     ul_usb1_delete(dev);
+//
+//     info("USB Skeleton now disconnected");
+// }
+
+// static struct usb_driver ul_usb1_driver = {
+//     .name =         "ul_usb1-can",
+//     .id_table = ul_usb1_table,
+//     .probe =        ul_usb1_probe,
+//     .disconnect =   ul_usb1_disconnect,
+//     .id_table =     ul_usb1_table,
+// };
+
+// int ul_usb1_init(void){
+//     return usb_register(&ul_usb1_driver);
+// }
+//
+// void ul_usb1_exit(void){
+//     usb_deregister(&ul_usb1_driver);
+// }
diff --git a/embedded/app/usbcan/usb/usb_defs.h b/embedded/app/usbcan/usb/usb_defs.h
new file mode 100644 (file)
index 0000000..48dde4e
--- /dev/null
@@ -0,0 +1,452 @@
+
+#ifndef USB_DEFS_MODULE
+  #define USB_DEFS_MODULE
+
+  #include <usb/usb_spec.h>
+//  #include <usb/pdiusb.h>
+  #include <usb/lpcusb.h>
+  #include <endian.h>
+  #include <cpu_def.h>
+
+  #include <endian.h>
+  #if __BYTE_ORDER == __BIG_ENDIAN
+    #include <byteswap.h>
+    #define SWAP(x) ((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF))
+  #else /*__LITTLE_ENDIAN*/
+    #define SWAP(x) (x)
+  #endif
+
+  #ifndef CODE
+    #define CODE
+  #endif
+
+       #ifdef USB_MAX_PACKET
+               #undef USB_MAX_PACKET
+               #define USB_MAX_PACKET 16
+       #endif
+/*****************************************************/
+/*** Static data structures for device descriptors ***/
+/*****************************************************/
+#ifndef USB_VENDOR_ID
+  #define USB_VENDOR_ID      0x1669  /* vymyslene cislo ( snad ho nikdo nema ... ;-) */
+#endif
+#ifndef USB_PRODUCT_ID
+  #define USB_PRODUCT_ID     0x1011  /* test code for ULAD21 */
+#endif
+  #define USB_RELEASE_VER    0x0010
+
+/*** Class codes for device description ***/
+  #define USB_CLASS_CODE      0xFF
+  #define USB_SUBCLASS_CODE   0x00
+  #define USB_PROTOCOL_CODE   0x00
+
+
+  #define NUM_ENDPOINTS  2
+  #define CONFIG_DESCRIPTOR_LENGTH sizeof( USB_CONFIGURATION_DESCRIPTOR) \
+                                     + sizeof( USB_INTERFACE_DESCRIPTOR) \
+                                     + ( NUM_ENDPOINTS * sizeof( USB_ENDPOINT_DESCRIPTOR))
+
+/*** Device descriptor ***/
+  CODE const USB_DEVICE_DESCRIPTOR DeviceDescription = {
+    sizeof( USB_DEVICE_DESCRIPTOR),
+    USB_DESCRIPTOR_TYPE_DEVICE,
+    SWAP( 0x0100),
+    USB_CLASS_CODE,
+    USB_SUBCLASS_CODE,
+    USB_PROTOCOL_CODE,
+    USB_MAX_PACKET0,
+    SWAP( USB_VENDOR_ID),
+    SWAP( USB_PRODUCT_ID),
+    SWAP( USB_RELEASE_VER),
+    1, /* manufacturer string ID */
+    2, /* product string ID */
+    3, /* serial number string ID */
+    1
+  };
+
+/*** All In Configuration 0 ***/
+  CODE const struct {
+    USB_CONFIGURATION_DESCRIPTOR configuration;
+    USB_INTERFACE_DESCRIPTOR interface;
+    USB_ENDPOINT_DESCRIPTOR endpoint_tx;
+    USB_ENDPOINT_DESCRIPTOR endpoint_rx;
+  } ConfigDescription = {
+    /*** Configuration descriptor ***/
+    {
+      sizeof( USB_CONFIGURATION_DESCRIPTOR),
+      USB_DESCRIPTOR_TYPE_CONFIGURATION,
+      SWAP( CONFIG_DESCRIPTOR_LENGTH),
+      1, /* cnt of interfaces */
+      1, /* this configuration ID */
+      4, /* config.name string ID*/
+      0x80, /* cfg, in spec is, taha bit 7 must be set to one -> 0xe0 , orig 0x60*/
+      0x32    /* device power current from host 100mA */
+    },
+    /*** Interface Descriptor ***/
+    {
+      sizeof( USB_INTERFACE_DESCRIPTOR),
+      USB_DESCRIPTOR_TYPE_INTERFACE,
+      0,    /* index of this interface for SetInterface request */
+      0,    /* ID alternate interface */
+      NUM_ENDPOINTS,
+      USB_CLASS_CODE,
+      USB_SUBCLASS_CODE,
+      USB_PROTOCOL_CODE,
+      5
+    },
+    /*** Endpoint 1 - Tx,Bulk ***/
+    {
+      sizeof( USB_ENDPOINT_DESCRIPTOR),
+      USB_DESCRIPTOR_TYPE_ENDPOINT,
+      0x01,
+      USB_ENDPOINT_TYPE_BULK,
+      SWAP( USB_MAX_PACKET),
+      0
+    },
+    /*** Endpoint 1 - Rx,Bulk ***/
+    {
+      sizeof( USB_ENDPOINT_DESCRIPTOR),
+      USB_DESCRIPTOR_TYPE_ENDPOINT,
+      0x81,
+      USB_ENDPOINT_TYPE_BULK,
+      SWAP( USB_MAX_PACKET),
+      0
+    }
+  };
+  /*** Strings - in unicode ***/
+  CODE const char Str0Desc[] = {  /* supported languages of strings */
+    4, 0x03,  /* 2+2*N , N is count of supported languages */
+    0x09,0x04 /* english 0x0409 */
+  };
+
+  CODE const char Str1Desc[] = {  /* 1 = manufacturer */
+    48,0x03,
+    'S',0,
+    'm',0,
+    'o',0,
+    'l',0,
+    'i',0,
+    'k',0,
+    ',',0,
+    'B',0,
+    'a',0,
+    'r',0,
+    't',0,
+    'o',0,
+    's',0,
+    'i',0,
+    'n',0,
+    's',0,
+    'k',0,
+    'i',0,
+    ',',0,
+    'P',0,
+    'i',0,
+    's',0,
+    'a',0
+  };
+
+  CODE const char Str2Desc[] = {  /* 2 = product */
+    38, 0x03,
+    'u',0,
+    'L',0,
+    'a',0,
+    'n',0,
+    '2',0,
+    'u',0,
+    's',0,
+    'b',0,
+    ' ',0,
+    'c',0,
+    'o',0,
+    'n',0,
+    'v',0,
+    'e',0,
+    'r',0,
+    't',0,
+    'o',0,
+    'r',0
+  };
+
+
+  CODE const char Str3Desc[] = {  /* 3 = version */
+    26, 0x03,
+    '2',0,
+    '3',0,
+    '.',0,
+    '0',0,
+    '7',0,
+    '.',0,
+    '0',0,
+    '4',0,
+    '-',0,
+    '1',0,
+    '.',0,
+    '1',0
+  };
+  CODE const char Str4Desc[] = {  /* 4 = configuration */
+    34, 0x03,
+    'C',0,
+    'o',0,
+    'n',0,
+    'f',0,
+    'i',0,
+    'g',0,
+    'u',0,
+    'r',0,
+    'a',0,
+    't',0,
+    'i',0,
+    'o',0,
+    'n',0,
+    ' ',0,
+    '#',0,
+    '1',0
+  };
+  CODE const char Str5Desc[] = {  /* 5 = interface */
+    26,0x03,
+    'I',0,
+    'n',0,
+    't',0,
+    'e',0,
+    'r',0,
+    'f',0,
+    'a',0,
+    'c',0,
+    'e',0,
+    ' ',0,
+    '#',0,
+    '0',0
+  };
+
+  CODE const char Str6Desc[] = {  /* EP1 OUT descriptor */
+    136,0x03,
+    'E',0,
+    'P',0,
+    '1',0,
+    'O',0,
+    'U',0,
+    'T',0,
+    '-',0,
+    's',0,
+    'e',0,
+    'n',0,
+    'd',0,
+    ' ',0,
+    'm',0,
+    'e',0,
+    's',0,
+    's',0,
+    'a',0,
+    'g',0,
+    'e',0,
+    '-',0,
+    'd',0,
+    'a',0,
+    'd',0,
+    'r',0,
+    ',',0,
+    's',0,
+    'a',0,
+    'd',0,
+    'r',0,
+    ',',0,
+    'c',0,
+    'm',0,
+    'd',0,
+    ',',0,
+    'f',0,
+    'l',0,
+    'g',0,
+    ',',0,
+    's',0,
+    't',0,
+    'a',0,
+    'm',0,
+    'p',0,
+    ',',0,
+    'f',0,
+    'r',0,
+    'e',0,
+    'e',0,
+    ',',0,
+    'l',0,
+    'e',0,
+    'n',0,
+    '-',0,
+    'l',0,
+    'o',0,
+    ',',0,
+    'l',0,
+    'e',0,
+    'n',0,
+    '-',0,
+    'h',0,
+    'i',0,
+    ',',0,
+    'd',0,
+    'a',0,
+    't',0,
+    'a',0
+  };
+
+  CODE const char Str7Desc[] = {  /* EP2 IN descriptor */
+    140,0x03,
+    'E',0,
+    'P',0,
+    '1',0,
+    'I',0,
+    'N',0,
+    '-',0,
+    'r',0,
+    'e',0,
+    'c',0,
+    'e',0,
+    'i',0,
+    'v',0,
+    'e',0,
+    ' ',0,
+    'm',0,
+    'e',0,
+    's',0,
+    's',0,
+    'a',0,
+    'g',0,
+    'e',0,
+    '-',0,
+    'd',0,
+    'a',0,
+    'd',0,
+    'r',0,
+    ',',0,
+    's',0,
+    'a',0,
+    'd',0,
+    'r',0,
+    ',',0,
+    'c',0,
+    'm',0,
+    'd',0,
+    ',',0,
+    'f',0,
+    'l',0,
+    'g',0,
+    ',',0,
+    's',0,
+    't',0,
+    'a',0,
+    'm',0,
+    'p',0,
+    ',',0,
+    'f',0,
+    'r',0,
+    'e',0,
+    'e',0,
+    ',',0,
+    'l',0,
+    'e',0,
+    'n',0,
+    '-',0,
+    'l',0,
+    'o',0,
+    ',',0,
+    'l',0,
+    'e',0,
+    'n',0,
+    '-',0,
+    'h',0,
+    'i',0,
+    ',',0,
+    'd',0,
+    'a',0,
+    't',0,
+    'a',0
+  };
+
+  CODE const char Str8Desc[] = {  /* EP1 OUT descriptor */
+    136,0x03,
+    'E',0,
+    'P',0,
+    '2',0,
+    'O',0,
+    'U',0,
+    'T',0,
+    '-',0,
+    's',0,
+    'e',0,
+    'n',0,
+    'd',0,
+    ' ',0,
+    'm',0,
+    'e',0,
+    's',0,
+    's',0,
+    'a',0,
+    'g',0,
+    'e',0,
+    '-',0,
+    'd',0,
+    'a',0,
+    'd',0,
+    'r',0,
+    ',',0,
+    's',0,
+    'a',0,
+    'd',0,
+    'r',0,
+    ',',0,
+    'c',0,
+    'm',0,
+    'd',0,
+    ',',0,
+    'f',0,
+    'l',0,
+    'g',0,
+    ',',0,
+    's',0,
+    't',0,
+    'a',0,
+    'm',0,
+    'p',0,
+    ',',0,
+    'f',0,
+    'r',0,
+    'e',0,
+    'e',0,
+    ',',0,
+    'l',0,
+    'e',0,
+    'n',0,
+    '-',0,
+    'l',0,
+    'o',0,
+    ',',0,
+    'l',0,
+    'e',0,
+    'n',0,
+    '-',0,
+    'h',0,
+    'i',0,
+    ',',0,
+    'd',0,
+    'a',0,
+    't',0,
+    'a',0
+  };
+
+  #define CNT_STRINGS 0x09
+
+  /* all strings in pointers array */
+  CODE const PUSB_STRING_DESCRIPTOR StringDescriptors[] = {
+    (PUSB_STRING_DESCRIPTOR) Str0Desc,
+    (PUSB_STRING_DESCRIPTOR) Str1Desc,
+    (PUSB_STRING_DESCRIPTOR) Str2Desc,
+    (PUSB_STRING_DESCRIPTOR) Str3Desc,
+    (PUSB_STRING_DESCRIPTOR) Str4Desc,
+    (PUSB_STRING_DESCRIPTOR) Str5Desc,
+    (PUSB_STRING_DESCRIPTOR) Str6Desc,
+    (PUSB_STRING_DESCRIPTOR) Str7Desc,
+    (PUSB_STRING_DESCRIPTOR) Str8Desc
+  };
+
+#endif /* USB_DEFS_MODULE */
diff --git a/embedded/app/usbcan/usb/usb_vend.h b/embedded/app/usbcan/usb/usb_vend.h
new file mode 100644 (file)
index 0000000..30835d0
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef USBCAN_VENDOR
+#define USBCAN_VENDOR
+
+#include <usb/usb.h>
+
+#define USBCAN_VENDOR_BAUD_RATE_SET    (1)
+#define USBCAN_VENDOR_BAUD_RATE_STATUS (2)
+#define USBCAN_VENDOR_SET_BTREGS       (3)
+#define USBCAN_VENDOR_CHECK_TX_STAT    (4)
+#define USBCAN_VENDOR_START_CHIP       (5)
+#define USBCAN_VENDOR_STOP_CHIP        (6)
+#define USBCAN_VENDOR_EXT_MASK_SET     (7)
+#define USBCAN_VENDOR_EXT_MASK_STATUS  (8)
+
+int usbcan_vendor(usb_device_t *udev);
+
+int set_ext_mask_complete_fnc(struct usb_ep_t *ep, int status);
+
+#endif /* USBCAN_VENDOR */
diff --git a/embedded/app/usbcan/usb_srq.c b/embedded/app/usbcan/usb_srq.c
new file mode 100644 (file)
index 0000000..4299a83
--- /dev/null
@@ -0,0 +1,238 @@
+/*****************************************************/
+/***   Module : USB module                         ***/
+/***   Author : Roman Bartosinski (C) 28.04.2002   ***/
+/***   Modify : 08.08.2002, 16.04.2003             ***/
+/*****************************************************/
+
+#include <string.h>
+#include <cpu_def.h>
+#include <system_def.h>
+#include <usb/usb.h>
+#include <usb/usb_spec.h>
+#include <usb/usbdebug.h>
+#include <usb/usb_srq.h>
+#include <usb/usb_defs.h>
+#include <usb/lpcusb.h>
+
+//extern ul_dcnv_state_t ep1_dcnv_state;
+
+  // ****************************
+  int usb_stdreq_get_status( usb_device_t *udev)
+  {
+    unsigned char c,buf[2] = { 0, 0};
+    unsigned char epid = (unsigned char) udev->request.wIndex;
+    usb_ep_t *ep0 = &(udev->ep0);
+
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("GetStatus\n"));
+    switch( udev->request.bmRequestType & USB_RECIPIENT) {
+      case USB_RECIPIENT_DEVICE:
+        if ( udev->flags & USB_FLAG_REMOTE_WAKE) //.remote_wake_up == 1)
+          buf[0] = USB_GETSTATUS_REMOTE_WAKEUP_ENABLED | USB_GETSTATUS_SELF_POWERED;
+        else
+          buf[0] = USB_GETSTATUS_SELF_POWERED;
+        break;
+      case USB_RECIPIENT_INTERFACE:
+        break;
+      case USB_RECIPIENT_ENDPOINT:
+/*        if ( epid & USB_ENDPOINT_DIRECTION_MASK)
+          c = pdiSelectEp(pdiEp2Idx(epid)); // endpoint in
+        else
+          c = pdiSelectEp(pdiEp2Idx(epid));     // endpoint Out
+          #ifdef PDIUSBD12
+          buf[0] = (( c & PDI_SELEP_STALL) == PDI_SELEP_STALL);
+          #else
+          buf[0] = 0;
+          #endif*/
+        break;
+      default:
+        return USB_COMPLETE_FAIL;
+    }
+    usb_udev_write_endpoint( ep0, buf, 2);
+    return USB_COMPLETE_OK;
+  }
+
+  int usb_stdreq_clear_feature( usb_device_t *udev)
+  {
+    USB_DEVICE_REQUEST *dreq = &(udev->request);
+    unsigned char epid = (unsigned char) dreq->wIndex;
+
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("ClearFeature\n"));
+    switch( dreq->bmRequestType & USB_RECIPIENT) {
+      case USB_RECIPIENT_DEVICE:
+        if ( dreq->wValue == USB_FEATURE_REMOTE_WAKEUP) {
+          udev->flags &= ~USB_FLAG_REMOTE_WAKE; //.remote_wake_up = 0;
+          usb_udev_ack_setup( udev);
+          return USB_COMPLETE_OK;
+        }
+        break;
+      case USB_RECIPIENT_ENDPOINT:
+        if ( dreq->wValue == USB_FEATURE_ENDPOINT_STALL) {
+          lpc_usb_clrstallEP(epid);
+          usb_udev_ack_setup( udev);
+         //initialize state of ulan convertor
+         switch (epid&(USB_ENDPOINT_DIRECTION_MASK|0x03)) {
+           case 0x01:                          //rx USB -> tx ulan
+//           ul_freemsg(ep1_dcnv_state.tx_fd);
+//              ep1_dcnv_state.tx_2send=-1;
+             break;
+           case 0x81:                          //tx USB -> rx ulan
+//           ul_freemsg(ep1_dcnv_state.rx_fd);
+//              ep1_dcnv_state.rx_2rec=-1;
+//              ep1_dcnv_state.rx_wait4host=0;
+             break;
+         }
+          return USB_COMPLETE_OK;
+        }
+        break;
+    }
+    return USB_COMPLETE_FAIL;
+  }
+
+  int usb_stdreq_set_feature( usb_device_t *udev)
+  {
+    USB_DEVICE_REQUEST *dreq = &(udev->request);
+    unsigned char epid = (unsigned char) dreq->wIndex;
+
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("SetFeature\n"));
+    switch( dreq->bmRequestType & USB_RECIPIENT) {
+      case USB_RECIPIENT_DEVICE:
+        if ( dreq->wValue == USB_FEATURE_REMOTE_WAKEUP) {
+          udev->flags |= USB_FLAG_REMOTE_WAKE; //.remote_wake_up = 1;
+          lpc_usb_setstallEP (epid);
+          usb_udev_ack_setup( udev);
+          return USB_COMPLETE_OK;
+        }
+        break;
+      case USB_RECIPIENT_ENDPOINT:
+        if ( dreq->wValue == USB_FEATURE_ENDPOINT_STALL) {
+          usb_udev_ack_setup( udev);
+          return USB_COMPLETE_OK;
+        }
+        break;
+    }
+    return USB_COMPLETE_FAIL;
+  }
+
+  int usb_stdreq_set_address( usb_device_t *udev)
+  {
+    int adr;
+    USB_DEVICE_REQUEST *dreq = &(udev->request);
+    adr=dreq->wValue & DEVICE_ADDRESS_MASK;
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("SetAddr-%d\n",adr));
+    usb_udev_ack_setup( udev);
+    lpc_usb_set_addr(adr);
+    return USB_COMPLETE_OK;
+  }
+
+  int usb_stdreq_get_configuration( usb_device_t *udev)
+  {
+    unsigned char buf = udev->configuration; //usb_flags.configured;
+    usb_ep_t *ep0 = &(udev->ep0);
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("GetConfig\n"));
+    usb_udev_write_endpoint( ep0, &buf, 1);
+    return USB_COMPLETE_OK;
+  }
+
+  int usb_stdreq_set_configuration( usb_device_t *udev)
+  {
+    USB_DEVICE_REQUEST *dreq = &(udev->request);
+    unsigned char iCfg = dreq->wValue & 0xff;
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("SetConfig\n"));
+    if ( iCfg < 2) {       // put device in unconfigured state or set configuration 1 ( no else)
+      usb_udev_ack_setup( udev);
+      lpc_usb_config_device(iCfg);
+      if ( iCfg) {
+        udev->flags |= USB_FLAG_CONFIGURED;
+        lpc_usb_configEP(0x01,USB_MAX_PACKET0);
+        lpc_usb_configEP(0x81,USB_MAX_PACKET0);
+      } else {
+        udev->flags &= ~USB_FLAG_CONFIGURED;
+      }
+      udev->configuration = iCfg;  //usb_flags.configured = iCfg;
+      return USB_COMPLETE_OK;
+    } else
+      return USB_COMPLETE_FAIL;
+  }
+
+  int usb_stdreq_get_interface( usb_device_t *udev)
+  {
+    unsigned char buf = 0; /// udev->interface
+    usb_ep_t *ep0 = &(udev->ep0);
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("GetIface\n"));
+    usb_udev_write_endpoint( ep0, &buf, 1);
+    return USB_COMPLETE_OK;
+  }
+
+  int usb_stdreq_set_interface( usb_device_t *udev)
+  {
+    USB_DEVICE_REQUEST *dreq = &(udev->request);
+
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("SetIface\n"));
+    if (( dreq->wValue == 0) && ( dreq->wIndex == 0)) {
+      usb_udev_ack_setup( udev);
+      return USB_COMPLETE_OK;
+    } else {
+      return USB_COMPLETE_FAIL;
+    }
+  }
+
+  int usb_stdreq_get_descriptor( usb_device_t *udev)
+  {
+    unsigned char *pDesc;
+    unsigned short Len = 0;
+    USB_DEVICE_REQUEST *dreq = &(udev->request);
+    int i;
+
+    i = (dreq->wValue >> 8) & 0xff; /* MSB part of wValue */
+    usb_debug_print( DEBUG_LEVEL_HIGH, ("GetDesc\n"));
+    usb_debug_print( DEBUG_LEVEL_VERBOSE, ( " - %s desc.\n", /*(unsigned int)*/ usb_debug_get_std_descriptor(i)));
+
+    switch (i) {
+      case USB_DESCRIPTOR_TYPE_DEVICE:
+        pDesc = (unsigned char *)&DeviceDescription;
+        Len = sizeof( USB_DEVICE_DESCRIPTOR);
+        break;
+      case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+        pDesc = (unsigned char *)&ConfigDescription;
+        Len = CONFIG_DESCRIPTOR_LENGTH;
+        break;
+      case USB_DESCRIPTOR_TYPE_INTERFACE:
+        pDesc = (unsigned char *)&ConfigDescription.interface;
+        Len = sizeof( USB_INTERFACE_DESCRIPTOR);
+        break;
+      case USB_DESCRIPTOR_TYPE_STRING:
+        i = dreq->wValue & 0xff; /* LSB part of wValue */
+        /*printf("Get descriptor indx=0x%02x\n", i);*/
+        if ( i < CNT_STRINGS) {
+          pDesc = (unsigned char *) StringDescriptors[ i];
+          Len = *pDesc;
+          /*usb_debug_print(0,("indx=0x%02x ptr=%p len=%d : '%c'\n", i, pDesc, Len, pDesc[2]));*/
+        } else {
+          return USB_COMPLETE_FAIL;
+        }
+        break;
+      default:
+        return USB_COMPLETE_FAIL;
+    }
+    if ( dreq->wLength < Len) Len = dreq->wLength;
+    usb_send_control_data( udev, pDesc, Len);
+    return USB_COMPLETE_OK;
+  }
+
+
+/*
+  void usb_init_stdreq_fnc( usb_device_t *udev)
+  {
+    // memset( udev->stdreq, 0, sizeof(udev->stdreq));
+
+    udev->stdreq[USB_REQUEST_GET_STATUS] = usb_stdreq_get_status;
+    udev->stdreq[USB_REQUEST_CLEAR_FEATURE] = usb_stdreq_clear_feature;
+    udev->stdreq[USB_REQUEST_SET_FEATURE] = usb_stdreq_set_feature;
+    udev->stdreq[USB_REQUEST_SET_ADDRESS] = usb_stdreq_set_address;
+    udev->stdreq[USB_REQUEST_GET_DESCRIPTOR] = usb_stdreq_get_descriptor;
+    udev->stdreq[USB_REQUEST_GET_CONFIGURATION] = usb_stdreq_get_configuration;
+    udev->stdreq[USB_REQUEST_SET_CONFIGURATION] = usb_stdreq_set_configuration;
+    udev->stdreq[USB_REQUEST_GET_INTERFACE] = usb_stdreq_get_interface;
+    udev->stdreq[USB_REQUEST_SET_INTERFACE] = usb_stdreq_set_interface;
+  }
+*/
diff --git a/embedded/app/usbcan/usb_vend.c b/embedded/app/usbcan/usb_vend.c
new file mode 100644 (file)
index 0000000..29cd74b
--- /dev/null
@@ -0,0 +1,181 @@
+// #define CAN_DEBUG
+
+#include <stdio.h>
+#include <system_def.h>
+#include <hal_intr.h>
+#include "./can/can.h"
+#include "./can/can_sysless.h"
+#include "./can/main.h"
+#include "./can/devcommon.h"
+#include "./usb/usb_vend.h"
+#include "./can/ul_usb1.h"
+#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+  #include <byteswap.h>
+#endif
+
+extern struct canuser_t *canuser;
+extern uint8_t vendor_ret;
+
+int set_ext_mask_complete_fnc(struct usb_ep_t *ep, int status){
+  int dest_chip;
+
+       unsigned long code;
+       unsigned long mask;
+
+       struct ul_usb1_chip_data *chip_data=NULL;
+
+       usb_device_t *udev=ep->udev;
+       unsigned char *data=ep->ptr - ep->actual;
+
+       if (udev->request.bRequest==USBCAN_VENDOR_EXT_MASK_SET){
+               dest_chip=(udev->request.wIndex);
+               if ((dest_chip>=MAX_TOT_CHIPS)||(dest_chip<0))
+                       goto error;
+               if (!chips_p[dest_chip])
+                       goto error;
+               if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL)
+                       goto nodata;
+
+               mask=*(uint32_t *)(data);
+               code=*(uint32_t *)(data+4);
+               #if __BYTE_ORDER == __BIG_ENDIAN
+               mask  = bswap_32( mask);
+               code  = bswap_32( code);
+               #endif
+
+
+               if (chips_p[dest_chip]->chipspecops->extended_mask(chips_p[dest_chip], code, mask)<0)
+                       goto error;
+               chip_data->flags |= UL_USB1_CHIP_MASK_SET;
+       }
+       return 0;
+error:
+       chip_data->flags &= ~UL_USB1_CHIP_MASK_SET;
+nodata:
+       return -1;
+}
+
+int set_baud_rate_complete_fnc(struct usb_ep_t *ep, int status){
+  int dest_chip;
+
+       int32_t rate,sjw,sampl_pt,flags;
+
+       struct ul_usb1_chip_data *chip_data=NULL;
+
+       usb_device_t *udev=ep->udev;
+       unsigned char *data=ep->ptr - ep->actual;
+
+       if (udev->request.bRequest==USBCAN_VENDOR_BAUD_RATE_SET){
+               dest_chip=(udev->request.wIndex);
+               if ((dest_chip>=MAX_TOT_CHIPS)||(dest_chip<0))
+                       goto error;
+               if (!chips_p[dest_chip])
+                       goto error;
+               if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL)
+                       goto nodata;
+
+               rate=*(int32_t *)(data);
+               sjw=*(int32_t *)(data+4);
+               sampl_pt=*(int32_t *)(data+8);
+               flags=*(int32_t *)(data+12);
+               #if __BYTE_ORDER == __BIG_ENDIAN
+               rate  = bswap_32( rate);
+               sjw  = bswap_32( sjw);
+               sampl_pt  = bswap_32( sampl_pt);
+               flags  = bswap_32( flags);
+               #endif
+
+               if (chips_p[dest_chip]->chipspecops->baud_rate(chips_p[dest_chip], rate, chips_p[dest_chip]->clock, sjw, sampl_pt, flags)<0)
+                       goto error;
+               chip_data->flags |= UL_USB1_CHIP_BAUD_SET;
+       }
+       return 0;
+error:
+       chip_data->flags &= ~UL_USB1_CHIP_BAUD_SET;
+nodata:
+       return -1;
+}
+
+int usbcan_vendor(usb_device_t *udev)
+{
+  // wIndex, wValue, bRequest, wLength
+  int dest_chip;
+  struct ul_usb1_chip_data *chip_data;
+
+  dest_chip=(udev->request.wIndex);
+  if ((dest_chip>=MAX_TOT_CHIPS)||(dest_chip<0))
+       return -1; // Should look like ok (0) or stall (-1)?
+  if (!chips_p[dest_chip])
+       return -1; // Should look like ok (0) or stall (-1)?
+
+  switch ( udev->request.bRequest) {
+               case USBCAN_VENDOR_EXT_MASK_SET:
+                       udev->ep0.complete_fnc=set_ext_mask_complete_fnc;
+                       return 1;
+               case USBCAN_VENDOR_EXT_MASK_STATUS:
+                       vendor_ret=-1;
+                       if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL)
+                               usb_send_control_data(udev,&vendor_ret,1);
+                       else{
+                               vendor_ret=(chip_data->flags & UL_USB1_CHIP_MASK_SET)?1:0;
+                               usb_send_control_data(udev,&vendor_ret,1);
+                       }
+                       chip_data->flags &= ~UL_USB1_CHIP_MASK_SET;
+                       return 1;
+
+               case USBCAN_VENDOR_BAUD_RATE_SET:
+                       udev->ep0.complete_fnc=set_baud_rate_complete_fnc;
+                       return 1;
+               case USBCAN_VENDOR_BAUD_RATE_STATUS:
+                       vendor_ret=-1;
+                       if ((chip_data=((struct ul_usb1_chip_data*)(chips_p[dest_chip]->chip_data)))==NULL)
+                               usb_send_control_data(udev,&vendor_ret,1);
+                       else{
+                               vendor_ret=(chip_data->flags & UL_USB1_CHIP_BAUD_SET)?1:0;
+                               usb_send_control_data(udev,&vendor_ret,1);
+                       }
+                       chip_data->flags &= ~UL_USB1_CHIP_BAUD_SET;
+                       return 1;
+
+               case USBCAN_VENDOR_SET_BTREGS:
+                       {
+                               uint16_t value=udev->request.wValue;
+                               vendor_ret=1;
+                               if (chips_p[dest_chip]->chipspecops->set_btregs(chips_p[dest_chip],value&0xFF,(value>>8)&0xFF)<0)
+                                       vendor_ret=0;
+                               usb_send_control_data(udev,&vendor_ret,1);
+                       }
+             &nbs