]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
merged branches/netlink in rev. 1037 back to trunk.
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Fri, 21 Aug 2009 10:00:21 +0000 (10:00 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Fri, 21 Aug 2009 10:00:21 +0000 (10:00 +0000)
git-svn-id: svn://svn.berlios.de//socketcan/trunk@1038 030b6a49-0b11-0410-94ab-b0dab22257f2

77 files changed:
FILES-2.6-ALL
kernel/2.6/Documentation/networking/can.txt
kernel/2.6/Makefile
kernel/2.6/README.known-issues [new file with mode: 0644]
kernel/2.6/drivers/net/can/Kconfig
kernel/2.6/drivers/net/can/Makefile
kernel/2.6/drivers/net/can/at91_can.c
kernel/2.6/drivers/net/can/cc770/Makefile [new file with mode: 0644]
kernel/2.6/drivers/net/can/cc770/cc770.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/cc770/cc770.h [new file with mode: 0644]
kernel/2.6/drivers/net/can/cc770/cc770_isa.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/cc770/cc770_of_platform.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/dev.c
kernel/2.6/drivers/net/can/esd_pci331.c
kernel/2.6/drivers/net/can/mcp251x.c
kernel/2.6/drivers/net/can/mscan/Makefile
kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c
kernel/2.6/drivers/net/can/mscan/mscan.c
kernel/2.6/drivers/net/can/mscan/mscan.h
kernel/2.6/drivers/net/can/old/ccan/Makefile
kernel/2.6/drivers/net/can/old/ccan/ccan.c
kernel/2.6/drivers/net/can/old/ccan/ccan.h
kernel/2.6/drivers/net/can/old/ccan/h7202_can.c
kernel/2.6/drivers/net/can/old/i82527/i82527.c
kernel/2.6/drivers/net/can/old/i82527/proc.c
kernel/2.6/drivers/net/can/old/mscan/mpc52xx_can.c
kernel/2.6/drivers/net/can/old/mscan/mscan.c
kernel/2.6/drivers/net/can/old/sja1000/proc.c
kernel/2.6/drivers/net/can/old/sja1000/sja1000.c
kernel/2.6/drivers/net/can/sja1000/Makefile
kernel/2.6/drivers/net/can/sja1000/ems_104m.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/ems_pci.c
kernel/2.6/drivers/net/can/sja1000/ems_pcmcia.c
kernel/2.6/drivers/net/can/sja1000/esd_pci.c
kernel/2.6/drivers/net/can/sja1000/ixxat_pci.c
kernel/2.6/drivers/net/can/sja1000/kvaser_pci.c
kernel/2.6/drivers/net/can/sja1000/peak_pci.c
kernel/2.6/drivers/net/can/sja1000/pipcan.c
kernel/2.6/drivers/net/can/sja1000/sja1000.c
kernel/2.6/drivers/net/can/sja1000/sja1000.h
kernel/2.6/drivers/net/can/sja1000/sja1000_isa.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sja1000/sja1000_of_platform.c
kernel/2.6/drivers/net/can/sja1000/sja1000_platform.c
kernel/2.6/drivers/net/can/slcan.c
kernel/2.6/drivers/net/can/softing/Makefile
kernel/2.6/drivers/net/can/softing/softing.h
kernel/2.6/drivers/net/can/softing/softing_cs.c
kernel/2.6/drivers/net/can/softing/softing_fw.c
kernel/2.6/drivers/net/can/softing/softing_main.c
kernel/2.6/drivers/net/can/softing/softing_sysfs.c [new file with mode: 0644]
kernel/2.6/drivers/net/can/sysfs.c
kernel/2.6/drivers/net/can/sysfs.h
kernel/2.6/drivers/net/can/vcan.c
kernel/2.6/include/linux/can/dev.h
kernel/2.6/include/linux/can/netlink.h [new file with mode: 0644]
kernel/2.6/include/linux/can/platform/sja1000.h
kernel/2.6/include/socketcan/can.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/bcm.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/core.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/dev.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/error.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/ioctl.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/isotp.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/netlink.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/platform/mcp251x.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/platform/sja1000.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/raw.h [new file with mode: 0644]
kernel/2.6/include/socketcan/can/version.h [new file with mode: 0644]
kernel/2.6/net/can/af_can.c
kernel/2.6/net/can/af_can.h
kernel/2.6/net/can/bcm-prior-2-6-22.c
kernel/2.6/net/can/bcm.c
kernel/2.6/net/can/compat.h
kernel/2.6/net/can/isotp.c
kernel/2.6/net/can/proc.c
kernel/2.6/net/can/raw.c
strip-src

index 08051a38688ab66c707e7ce3246094cf2b4b808d..76f1dc0aa5401c1526eddf150c1531aeb79fd38d 100644 (file)
@@ -27,6 +27,7 @@ kernel/2.6/drivers/net/can/softing/Makefile
 kernel/2.6/drivers/net/can/dev.c
 kernel/2.6/drivers/net/can/sysfs.h
 kernel/2.6/drivers/net/can/mcp251x.c
 kernel/2.6/drivers/net/can/dev.c
 kernel/2.6/drivers/net/can/sysfs.h
 kernel/2.6/drivers/net/can/mcp251x.c
+kernel/2.6/drivers/net/can/at91_can.c
 kernel/2.6/drivers/net/can/Makefile
 kernel/2.6/drivers/net/can/mscan/mscan.c
 kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c
 kernel/2.6/drivers/net/can/Makefile
 kernel/2.6/drivers/net/can/mscan/mscan.c
 kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c
index 2035bc4932f224685992ca57b29e64de5da4934e..6cd6627c3293ded2cf0d97ea1f3be4886182d223 100644 (file)
@@ -36,10 +36,15 @@ This file contains
     6.2 local loopback of sent frames
     6.3 CAN controller hardware filters
     6.4 The virtual CAN driver (vcan)
     6.2 local loopback of sent frames
     6.3 CAN controller hardware filters
     6.4 The virtual CAN driver (vcan)
-    6.5 currently supported CAN hardware
-    6.6 todo
+    6.5 The CAN network device driver interface
+      6.5.1 Netlink interface to set/get devices properties
+      6.5.2 Setting the CAN bit-timing
+      6.5.3 Starting and stopping the CAN network device
+    6.6 supported CAN hardware
 
 
-  7 Credits
+  7 Socket CAN resources
+
+  8 Credits
 
 ============================================================================
 
 
 ============================================================================
 
@@ -234,6 +239,8 @@ solution for a couple of reasons:
   the user application using the common CAN filter mechanisms. Inside
   this filter definition the (interested) type of errors may be
   selected. The reception of error frames is disabled by default.
   the user application using the common CAN filter mechanisms. Inside
   this filter definition the (interested) type of errors may be
   selected. The reception of error frames is disabled by default.
+  The format of the CAN error frame is briefly decribed in the Linux
+  header file "include/linux/can/error.h".
 
 4. How to use Socket CAN
 ------------------------
 
 4. How to use Socket CAN
 ------------------------
@@ -605,61 +612,213 @@ solution for a couple of reasons:
   removal of vcan network devices can be managed with the ip(8) tool:
 
   - Create a virtual CAN network interface:
   removal of vcan network devices can be managed with the ip(8) tool:
 
   - Create a virtual CAN network interface:
-       ip link add type vcan
+       ip link add type vcan
 
   - Create a virtual CAN network interface with a specific name 'vcan42':
 
   - Create a virtual CAN network interface with a specific name 'vcan42':
-       ip link add dev vcan42 type vcan
+       ip link add dev vcan42 type vcan
 
   - Remove a (virtual CAN) network interface 'vcan42':
 
   - Remove a (virtual CAN) network interface 'vcan42':
-       ip link del vcan42
-
-  The tool 'vcan' from the SocketCAN SVN repository on BerliOS is obsolete.
-
-  Virtual CAN network device creation in older Kernels:
-  In Linux Kernel versions < 2.6.24 the vcan driver creates 4 vcan
-  netdevices at module load time by default. This value can be changed
-  with the module parameter 'numdev'. E.g. 'modprobe vcan numdev=8'
-
-  6.5 currently supported CAN hardware
+       $ ip link del vcan42
+
+  6.5 The CAN network device driver interface
+
+  The CAN network device driver interface provides a generic interface
+  to setup, configure and monitor CAN network devices. The user can then
+  configure the CAN device, like setting the bit-timing parameters, via
+  the netlink interface using the program "ip" from the "IPROUTE2"
+  utility suite. The following chapter describes briefly how to use it.
+  Furthermore, the interface uses a common data structure and exports a
+  set of common functions, which all real CAN network device drivers
+  should use. Please have a look to the SJA1000 or MSCAN driver to
+  understand how to use them. The name of the module is can-dev.ko.
+
+  6.5.1 Netlink interface to set/get devices properties
+
+  The CAN device must be configured via netlink interface. The supported
+  netlink message types are defined and briefly described in
+  "include/linux/can/netlink.h". CAN link support for the program "ip"
+  of the IPROUTE2 utility suite is avaiable and it can be used as shown
+  below:
+
+  - Setting CAN device properties:
+
+    $ ip link set can0 type can help
+    Usage: ip link set DEVICE type can
+       [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |
+       [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1
+         phase-seg2 PHASE-SEG2 [ sjw SJW ] ]
+
+       [ loopback { on | off } ]
+       [ listen-only { on | off } ]
+       [ triple-sampling { on | off } ]
+
+       [ restart-ms TIME-MS ]
+       [ restart ]
+
+       Where: BITRATE       := { 1..1000000 }
+              SAMPLE-POINT  := { 0.000..0.999 }
+              TQ            := { NUMBER }
+              PROP-SEG      := { 1..8 }
+              PHASE-SEG1    := { 1..8 }
+              PHASE-SEG2    := { 1..8 }
+              SJW           := { 1..4 }
+              RESTART-MS    := { 0 | NUMBER }
+
+  - Display CAN device details and statistics:
+
+    $ ip -details -statistics link show can0
+    2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP qlen 10
+      link/can
+      can <TRIPLE-SAMPLING> state ERROR-ACTIVE restart-ms 100
+      bitrate 125000 sample_point 0.875
+      tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
+      sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1
+      clock 8000000
+      re-started bus-errors arbit-lost error-warn error-pass bus-off
+      41         17457      0          41         42         41
+      RX: bytes  packets  errors  dropped overrun mcast
+      140859     17608    17457   0       0       0
+      TX: bytes  packets  errors  dropped carrier collsns
+      861        112      0       41      0       0
+
+  More info to the above output:
+
+    "<TRIPLE-SAMPLING>"
+       Shows the list of selected CAN controller modes: LOOPBACK,
+       LISTEN-ONLY, or TRIPLE-SAMPLING.
+
+    "state ERROR-ACTIVE"
+       The current state of the CAN controller: "ERROR-ACTIVE",
+       "ERROR-WARNING", "ERROR-PASSIVE", "BUS-OFF" or "STOPPED"
+
+    "restart-ms 100"
+       Automatic restart delay time. If set to a non-zero value, a
+       restart of the CAN controller will be triggered automatically
+       in case of a bus-off condition after the specified delay time
+       in milliseconds. By default it's off.
+
+    "bitrate 125000 sample_point 0.875"
+       Shows the real bit-rate in bits/sec and the sample-point in the
+       range 0.000..0.999. If the calculation of bit-timing parameters
+       is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the
+       bit-timing can be defined by setting the "bitrate" argument.
+       Optionally the "sample-point" can be specified. By default it's
+       0.000 assuming CIA-recommended sample-points.
+
+    "tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1"
+       Shows the time quanta in ns, propagation segment, phase buffer
+       segment 1 and 2 and the synchronisation jump width in units of
+       tq. They allow to define the CAN bit-timing in a hardware
+       independent format as proposed by the Bosch CAN 2.0 spec (see
+       chapter 8 of http://www.semiconductors.bosch.de/pdf/can2spec.pdf).
+
+    "sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1
+     clock 8000000"
+       Shows the bit-timing constants of the CAN controller, here the
+       "sja1000". The minimum and maximum values of the time segment 1
+       and 2, the synchronisation jump width in units of tq, the
+       bitrate pre-scaler and the CAN system clock frequency in Hz.
+       These constants could be used for user-defined (non-standard)
+       bit-timing calculation algorithms in user-space.
+
+    "re-started bus-errors arbit-lost error-warn error-pass bus-off"
+       Shows the number of restarts, bus and arbitration lost errors,
+       and the state changes to the error-warning, error-passive and
+       bus-off state. RX overrun errors are listed in the "overrun"
+       field of the standard network statistics.
+
+  6.5.2 Setting the CAN bit-timing
+
+  The CAN bit-timing parameters can always be defined in a hardware
+  independent format as proposed in the Bosch CAN 2.0 specification
+  specifying the arguments "tq", "prop_seg", "phase_seg1", "phase_seg2"
+  and "sjw":
+
+    $ ip link set canX type can tq 125 prop-seg 6 \
+                               phase-seg1 7 phase-seg2 2 sjw 1
+
+  If the kernel option CONFIG_CAN_CALC_BITTIMING is enabled, CIA
+  recommended CAN bit-timing parameters will be calculated if the bit-
+  rate is specified with the argument "bitrate":
+
+    $ ip link set canX type can bitrate 125000
+
+  Note that this works fine for the most common CAN controllers with
+  standard bit-rates but may *fail* for exotic bit-rates or CAN system
+  clock frequencies. Disabling CONFIG_CAN_CALC_BITTIMING saves some
+  space and allows user-space tools to solely determine and set the
+  bit-timing parameters. The CAN controller specific bit-timing
+  constants can be used for that purpose. They are listed by the
+  following command:
+
+    $ ip -details link show can0
+    ...
+      sja1000: clock 8000000 tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1
+
+  6.5.3 Starting and stopping the CAN network device
+
+  A CAN network device is started or stopped as usual with the command
+  "ifconfig canX up/down" or "ip link set canX up/down". Be aware that
+  you *must* define proper bit-timing parameters for real CAN devices
+  before you can start it to avoid error-prone default settings:
+
+    $ ip link set canX up type can bitrate 125000
+
+  A device may enter the "bus-off" state if too much errors occurred on
+  the CAN bus. Then no more messages are received or sent. An automatic
+  bus-off recovery can be enabled by setting the "restart-ms" to a
+  non-zero value, e.g.:
+
+    $ ip link set canX type can restart-ms 100
+
+  Alternatively, the application may realize the "bus-off" condition
+  by monitoring CAN error frames and do a restart when appropriate with
+  the command:
+
+    $ ip link set canX type can restart
+
+  Note that a restart will also create a CAN error frame (see also
+  chapter 3.4).
 
 
-  On the project website http://developer.berlios.de/projects/socketcan
-  there are different drivers available:
+  6.6 Supported CAN hardware
 
 
-    vcan:    Virtual CAN interface driver (if no real hardware is available)
-    sja1000: Philips SJA1000 CAN controller (recommended)
-    i82527:  Intel i82527 CAN controller
-    mscan:   Motorola/Freescale CAN controller (e.g. inside SOC MPC5200)
-    ccan:    CCAN controller core (e.g. inside SOC h7202)
-    slcan:   For a bunch of CAN adaptors that are attached via a
-             serial line ASCII protocol (for serial / USB adaptors)
+  Please check the "Kconfig" file in "drivers/net/can" to get an actual
+  list of the support CAN hardware. On the Socket CAN project website
+  (see chapter 7) there might be further drivers available, also for
+  older kernel versions.
 
 
-  Additionally the different CAN adaptors (ISA/PCI/PCMCIA/USB/Parport)
-  from PEAK Systemtechnik support the CAN netdevice driver model
-  since Linux driver v6.0: http://www.peak-system.com/linux/index.htm
+7. Socket CAN resources
+-----------------------
 
 
-  Please check the Mailing Lists on the berlios OSS project website.
+  You can find further resources for Socket CAN like user space tools,
+  support for old kernel versions, more drivers, mailing lists, etc.
+  at the BerliOS OSS project website for Socket CAN:
 
 
-  6.6 todo
+    http://developer.berlios.de/projects/socketcan
 
 
-  The configuration interface for CAN network drivers is still an open
-  issue that has not been finalized in the socketcan project. Also the
-  idea of having a library module (candev.ko) that holds functions
-  that are needed by all CAN netdevices is not ready to ship.
-  Your contribution is welcome.
+  If you have questions, bug fixes, etc., don't hesitate to post them to
+  the Socketcan-Users mailing list. But please search the archives first.
 
 
-7. Credits
+8. Credits
 ----------
 
 ----------
 
-  Oliver Hartkopp (PF_CAN core, filters, drivers, bcm)
+  Oliver Hartkopp (PF_CAN core, filters, drivers, bcm, SJA1000 driver)
   Urs Thuermann (PF_CAN core, kernel integration, socket interfaces, raw, vcan)
   Jan Kizka (RT-SocketCAN core, Socket-API reconciliation)
   Urs Thuermann (PF_CAN core, kernel integration, socket interfaces, raw, vcan)
   Jan Kizka (RT-SocketCAN core, Socket-API reconciliation)
-  Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews)
+  Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews,
+                       CAN device driver interface, MSCAN driver)
   Robert Schwebel (design reviews, PTXdist integration)
   Marc Kleine-Budde (design reviews, Kernel 2.6 cleanups, drivers)
   Benedikt Spranger (reviews)
   Thomas Gleixner (LKML reviews, coding style, posting hints)
   Robert Schwebel (design reviews, PTXdist integration)
   Marc Kleine-Budde (design reviews, Kernel 2.6 cleanups, drivers)
   Benedikt Spranger (reviews)
   Thomas Gleixner (LKML reviews, coding style, posting hints)
-  Andrey Volkov (kernel subtree structure, ioctls, mscan driver)
+  Andrey Volkov (kernel subtree structure, ioctls, MSCAN driver)
   Matthias Brukner (first SJA1000 CAN netdevice implementation Q2/2003)
   Klaus Hitschler (PEAK driver integration)
   Uwe Koppe (CAN netdevices with PF_PACKET approach)
   Michael Schulze (driver layer loopback requirement, RT CAN drivers review)
   Matthias Brukner (first SJA1000 CAN netdevice implementation Q2/2003)
   Klaus Hitschler (PEAK driver integration)
   Uwe Koppe (CAN netdevices with PF_PACKET approach)
   Michael Schulze (driver layer loopback requirement, RT CAN drivers review)
+  Pavel Pisa (Bit-timing calculation)
+  Sascha Hauer (SJA1000 platform driver)
+  Sebastian Haas (SJA1000 EMS PCI driver)
+  Markus Plessing (SJA1000 EMS PCI driver)
+  Per Dalen (SJA1000 Kvaser PCI driver)
+  Sam Ravnborg (reviews, coding style, kbuild help)
index cb806ef8abea8313f93feba707b2c32ba0dae295..5a79e6ef7be5031f06fc0d6605e72f053c3aa4c9 100644 (file)
@@ -5,13 +5,24 @@ PWD       := $(shell pwd)
 TOPDIR    := $(PWD)
 
 export CONFIG_CAN_VCAN=m
 TOPDIR    := $(PWD)
 
 export CONFIG_CAN_VCAN=m
+export CONFIG_CAN_SLCAN=m
 export CONFIG_CAN_DEV=m
 export CONFIG_CAN_DEV=m
+export CONFIG_CAN_CALC_BITTIMING=y
+#export CONFIG_CAN_DEV_SYSFS=y
 #export CONFIG_CAN_SJA1000_OLD=m
 #export CONFIG_CAN_I82527_OLD=m
 export CONFIG_CAN_SJA1000=m
 export CONFIG_CAN_SJA1000_PLATFORM=m
 #export CONFIG_CAN_SJA1000_OLD=m
 #export CONFIG_CAN_I82527_OLD=m
 export CONFIG_CAN_SJA1000=m
 export CONFIG_CAN_SJA1000_PLATFORM=m
+#export CONFIG_CAN_SJA1000_OF_PLATFORM=m
+export CONFIG_CAN_ESD_PCI=m
+export CONFIG_CAN_IXXAT_PCI=m
+export CONFIG_CAN_PEAK_PCI=m
+export CONFIG_CAN_KVASER_PCI=m
 export CONFIG_CAN_EMS_PCI=m
 export CONFIG_CAN_EMS_PCMCIA=m
 export CONFIG_CAN_EMS_PCI=m
 export CONFIG_CAN_EMS_PCMCIA=m
+export CONFIG_CAN_EMS_104M=m
+export CONFIG_CAN_ESD_PCI=m
+export CONFIG_CAN_ESD_331=m
 export CONFIG_CAN_PIPCAN=m
 export CONFIG_CAN_SOFTING=m
 export CONFIG_CAN_SOFTING_CS=m
 export CONFIG_CAN_PIPCAN=m
 export CONFIG_CAN_SOFTING=m
 export CONFIG_CAN_SOFTING_CS=m
diff --git a/kernel/2.6/README.known-issues b/kernel/2.6/README.known-issues
new file mode 100644 (file)
index 0000000..a8a4e34
--- /dev/null
@@ -0,0 +1,29 @@
+This is a list of knwon driver issues:
+
+drivers/net/can/at91_can.c:
+  FIXME: bus-off handling
+  FIXME: review non-standard error counting and statistics
+  FIXME: to be tested
+
+drivers/net/can/mcp251x.c:
+
+  FIXME: echo support missing (requilred for IFF_ECHO)
+  FIXME: increment can_stats in case of state changes
+  FIXME: state changes by interrupt
+  FIXME: do_set_mode not implemented (required for restart)
+  FIXME: remove tx timeout callback
+  FIXME: to be tested
+
+drivers/net/can/softing/softing_main.c:
+
+  FIXME: coding style issues!
+  FIXME: check softing_flush_echo_skb and bus_off handling.
+  FIXME: to be tested
+
+drivers/net/can/mscan/mscan.c:
+  FIXME: don't use netdev->base_addr
+
+drivers/net/can/mscan/mpc52xx_can.c:
+
+  FIXME: add support for the MPC512x as well
+  FIXME: rename mpc52xx to mpc5xxx
index 4c711a0c6ab4fe18e18b3cde09e08e256273eebc..5ecca597becf7dcecf641adf497b9c9b1f32da65 100644 (file)
@@ -38,7 +38,7 @@ source "drivers/net/can/old/Kconfig"
 endif
 
 config CAN_DEV
 endif
 
 config CAN_DEV
-       tristate "Prompt for platform CAN drivers with sysfs support"
+       tristate "Prompt for platform CAN drivers with netlink support"
        depends on CAN && SYSFS
        default Y
        ---help---
        depends on CAN && SYSFS
        default Y
        ---help---
@@ -46,6 +46,16 @@ config CAN_DEV
          support. This is the standard library for CAN drivers.
          If unsure, say Y.
 
          support. This is the standard library for CAN drivers.
          If unsure, say Y.
 
+config CAN_DEV_SYSFS
+       bool "Support for sysfs interface (deprecated)"
+       depends on CAN_DEV && SYSFS
+       default N
+       ---help---
+         Adds support for the legacy sysfs interface to configure CAN
+         devices. If possible, please use the new netlink interface
+         instead.
+         If unsure, say N.
+
 config CAN_CALC_BITTIMING
        bool "CAN bit-timing calculation"
        depends on CAN_DEV
 config CAN_CALC_BITTIMING
        bool "CAN bit-timing calculation"
        depends on CAN_DEV
@@ -60,18 +70,43 @@ config CAN_CALC_BITTIMING
          files "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
          If unsure, say Y.
 
          files "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
          If unsure, say Y.
 
+config CAN_CC770
+       depends on HAS_IOMEM && CAN_DEV
+       tristate "Bosch CC770 and Intel AN82527"
+       ---help---
+         Driver for the Bosch CC770 and the compatible Intel AN82527
+         CAN controllers.
+
+config CAN_CC770_ISA
+       depends on CAN_CC770 && ISA
+       tristate "ISA Bus based legacy CC770 driver"
+       ---help---
+         This driver adds legacy support for CC770 and AN82527 chips
+         connected to the ISA bus using I/O port, memory mapped or
+         indirect access.
+
+config CAN_CC770_OF_PLATFORM
+       depends on CAN_CC770 && PPC_OF
+       tristate "Generic OF Platform Bus based CC770 driver"
+       ---help---
+         This driver adds support for the CC770 and other AN82527
+         compatible chips connected to the OpenFirmware "platform bus"
+         found on embedded systems with OpenFirmware bindings, e.g. if
+         you have a PowerPC based system you may want to enable this
+         option.
+
 config CAN_SJA1000
        depends on CAN_DEV
        tristate "Philips SJA1000"
        ---help---
 config CAN_SJA1000
        depends on CAN_DEV
        tristate "Philips SJA1000"
        ---help---
-         The SJA1000 is one of the top CAN controllers out there. As it
-         has a multiplexed interface it fits directly to 8051
-         microcontrollers or into the PC I/O port space. The SJA1000
-         is a full CAN controller, with shadow registers for RX and TX.
-         It can send and receive any kinds of CAN frames (SFF/EFF/RTR)
-         with a single (simple) filter setup.
+         Driver for the SJA1000 CAN controllers from Philips or NXP
 
 
-         This driver will use the new device interface.
+config CAN_SJA1000_ISA
+       depends on CAN_SJA1000 && ISA
+       tristate "ISA Bus based legacy SJA1000 driver"
+       ---help---
+         This driver adds legacy support for SJA1000 chips connected to
+         the ISA bus using I/O port, memory mapped or indirect access.
 
 config CAN_SJA1000_PLATFORM
        depends on CAN_SJA1000
 
 config CAN_SJA1000_PLATFORM
        depends on CAN_SJA1000
@@ -85,19 +120,20 @@ config CAN_SJA1000_PLATFORM
 
 config CAN_SJA1000_OF_PLATFORM
        depends on CAN_SJA1000 && PPC_OF
 
 config CAN_SJA1000_OF_PLATFORM
        depends on CAN_SJA1000 && PPC_OF
-       tristate "generic OF Platform Bus based SJA1000 driver"
+       tristate "Generic OF Platform Bus based SJA1000 driver"
        ---help---
          This driver adds support for the SJA1000 chips connected to
          the OpenFirmware "platform bus" found on embedded systems with
          OpenFirmware bindings, e.g. if you have a PowerPC based system
        ---help---
          This driver adds support for the SJA1000 chips connected to
          the OpenFirmware "platform bus" found on embedded systems with
          OpenFirmware bindings, e.g. if you have a PowerPC based system
-         you should enable this option.
+         you may want to enable this option.
 
 config CAN_EMS_PCI
 
 config CAN_EMS_PCI
-       tristate "EMS CPC-PCI and CPC-PCIe Card"
+       tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
        depends on PCI && CAN_SJA1000
        ---help---
        depends on PCI && CAN_SJA1000
        ---help---
-         This driver is for the one or two channel CPC-PCI and CPC-PCIe
-         cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+         This driver is for the one, two or four channel CPC-PCI,
+         CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
+         (http://www.ems-wuensche.de).
 
 config CAN_EMS_PCMCIA
        tristate "EMS CPC-CARD Card"
 
 config CAN_EMS_PCMCIA
        tristate "EMS CPC-CARD Card"
@@ -106,13 +142,20 @@ config CAN_EMS_PCMCIA
          This driver is for the one or two channel CPC-CARD cards from
          EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
 
          This driver is for the one or two channel CPC-CARD cards from
          EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
 
+config CAN_EMS_104M
+       tristate "EMS CPC-104M Card"
+       depends on ISA && CAN_SJA1000
+       ---help---
+         This driver is for the one, two or four channel CPC-104M cards
+         from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+
 config CAN_ESD_PCI
        tristate "ESD PCI Cards"
        depends on PCI && CAN_SJA1000
        ---help---
 config CAN_ESD_PCI
        tristate "ESD PCI Cards"
        depends on PCI && CAN_SJA1000
        ---help---
-         This driver supports the esd PCI CAN cards CAN-PCI/200, 
-         CAN-PCI/266, CAN-PMC/266 (PMC), CAN-CPCI/200 (CompactPCI), 
-         CAN-PCIe2000 (PCI Express) and CAN-PCI104/200 (PCI104) 
+         This driver supports the esd PCI CAN cards CAN-PCI/200,
+         CAN-PCI/266, CAN-PMC/266 (PMC), CAN-CPCI/200 (CompactPCI),
+         CAN-PCIe2000 (PCI Express) and CAN-PCI104/200 (PCI104)
          from the esd electronic system design gmbh (http://www.esd.eu).
 
 config CAN_IXXAT_PCI
          from the esd electronic system design gmbh (http://www.esd.eu).
 
 config CAN_IXXAT_PCI
@@ -145,7 +188,7 @@ config CAN_KVASER_PCI
 
 config CAN_ESD_PCI331
        tristate "ESD CAN 331 Cards"
 
 config CAN_ESD_PCI331
        tristate "ESD CAN 331 Cards"
-       depends on PCI
+       depends on PCI && CAN_DEV
        ---help---
          This driver supports the PCI/331, CPCI/331 and PMC/331 CAN cards
          from the esd system design gmbh (http://www.esd.eu).
        ---help---
          This driver supports the PCI/331, CPCI/331 and PMC/331 CAN cards
          from the esd system design gmbh (http://www.esd.eu).
@@ -155,10 +198,24 @@ config CAN_SOFTING
        depends on CAN_DEV
        ---help---
          generic softing CAN cards
        depends on CAN_DEV
        ---help---
          generic softing CAN cards
+         Sofing CAN cards come with 1 or 2 physical busses.
+         The API of the card does not allow fine control per bus, but
+         controls the 2 busses on the card together.
+         As such, some actions (start/stop/busoff recovery) on 1 bus
+         must bring down the other bus too temporarily.
+         You have been warned.
+         This driver is written on safe on 64bit, but not on big endian.
 
 config CAN_SOFTING_CS
        tristate "Softing CAN pcmcia cards"
        depends on CAN_SOFTING && PCMCIA
 
 config CAN_SOFTING_CS
        tristate "Softing CAN pcmcia cards"
        depends on CAN_SOFTING && PCMCIA
+       ---help---
+         Support for PCMCIA cards from Softing Gmbh & some cards
+         from Vector Gmbh.
+         You need firmware for these, which you can get at
+         http://developer.berlios.de/projects/socketcan/
+         This version of the driver is written against
+         firmware version 4.6
 
 config CAN_MSCAN
        depends on CAN_DEV && (PPC || M68K || M68KNOMMU)
 
 config CAN_MSCAN
        depends on CAN_DEV && (PPC || M68K || M68KNOMMU)
index ba023bd8fb5d95060c519c4aeadec1e8e077dc87..4fd9118777df196c75202124aebd3e9c8d1695fc 100644 (file)
@@ -13,6 +13,7 @@ export CONFIG_CAN_VCAN=m
 export CONFIG_CAN_DEV=m
 #export CONFIG_CAN_SJA1000_OLD=m
 #export CONFIG_CAN_I82527_OLD=m
 export CONFIG_CAN_DEV=m
 #export CONFIG_CAN_SJA1000_OLD=m
 #export CONFIG_CAN_I82527_OLD=m
+export CONFIG_CAN_CC770=m
 export CONFIG_CAN_SJA1000=m
 export CONFIG_CAN_SJA1000_PLATFORM=m
 export CONFIG_CAN_EMS_PCI=m
 export CONFIG_CAN_SJA1000=m
 export CONFIG_CAN_SJA1000_PLATFORM=m
 export CONFIG_CAN_EMS_PCI=m
@@ -34,8 +35,10 @@ obj-$(CONFIG_CAN_VCAN)               += vcan.o
 obj-$(CONFIG_CAN_SLCAN)                += slcan.o
 
 obj-$(CONFIG_CAN_DEV)          += can-dev.o
 obj-$(CONFIG_CAN_SLCAN)                += slcan.o
 
 obj-$(CONFIG_CAN_DEV)          += can-dev.o
-can-dev-y                      := dev.o sysfs.o
+can-dev-y                      := dev.o
+can-dev-$(CONFIG_CAN_DEV_SYSFS) += sysfs.o
 
 
+obj-$(CONFIG_CAN_CC770)                += cc770/
 obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_SOFTING)      += softing/
 obj-$(CONFIG_CAN_MSCAN)                += mscan/
 obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_SOFTING)      += softing/
 obj-$(CONFIG_CAN_MSCAN)                += mscan/
@@ -47,6 +50,14 @@ obj-$(CONFIG_CAN_MSCAN_OLD)  += old/mscan/
 obj-$(CONFIG_CAN_CCAN_OLD)     += old/ccan/
 obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
 
 obj-$(CONFIG_CAN_CCAN_OLD)     += old/ccan/
 obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
 
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+ifeq ($(CONFIG_CAN_DEBUG_DEVICES),y)
+       EXTRA_CFLAGS += -DDEBUG
+endif
+ifeq ($(CONFIG_CAN_DEV_SYSFS),y)
+       EXTRA_CFLAGS += -DCONFIG_CAN_DEV_SYSFS
+endif
+ifneq ($(CONFIG_CAN_CALC_BITTIMING),n)
+       EXTRA_CFLAGS += -DCONFIG_CAN_CALC_BITTIMING
+endif
 
 endif
 
 endif
index 2cb7746e5969d64e38e7911d403536ccb78b5d88..fdf82fbaa4bd7e144f3f338878ecdb43a8847f2b 100644 (file)
@@ -26,9 +26,9 @@
 #include <linux/init.h>
 #include <linux/clk.h>
 
 #include <linux/init.h>
 #include <linux/clk.h>
 
-#include <linux/can.h>
-#include <linux/can/error.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/error.h>
+#include <socketcan/can/dev.h>
 
 #include <mach/board.h>
 
 
 #include <mach/board.h>
 
@@ -153,6 +153,19 @@ struct at91_priv {
        unsigned int            tx_echo;
 
        unsigned int            rx_bank;
        unsigned int            tx_echo;
 
        unsigned int            rx_bank;
+       void __iomem            *reg_base; /* ioremap'ed address to registers */
+};
+
+
+static struct can_bittiming_const at91_bittiming_const = {
+       .tseg1_min = 4,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 2,
+       .brp_max = 128,
+       .brp_inc = 1,
 };
 
 
 };
 
 
@@ -174,13 +187,15 @@ static inline int get_tx_echo_mb(struct at91_priv *priv)
 
 static inline u32 at91_read(struct net_device *dev, enum at91_reg reg)
 {
 
 static inline u32 at91_read(struct net_device *dev, enum at91_reg reg)
 {
-       return readl((void __iomem *)dev->base_addr + reg);
+       struct at91_priv *priv = netdev_priv(dev);
+       return readl(priv->reg_base + reg);
 }
 
 static inline void
 at91_write(struct net_device *dev, enum at91_reg reg, u32 value)
 {
 }
 
 static inline void
 at91_write(struct net_device *dev, enum at91_reg reg, u32 value)
 {
-       writel(value, (void __iomem *)dev->base_addr + reg);
+       struct at91_priv *priv = netdev_priv(dev);
+       writel(value, priv->reg_base + reg);
 }
 
 
 }
 
 
@@ -255,7 +270,7 @@ static int at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
        else
                reg_mid = (cf->can_id & CAN_SFF_MASK) << 18;
 
        else
                reg_mid = (cf->can_id & CAN_SFF_MASK) << 18;
 
-       reg_mcr = (cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0 |
+       reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0 ) |
                (cf->can_dlc << 16) |
                AT91_MCR_MTCR;
 
                (cf->can_dlc << 16) |
                AT91_MCR_MTCR;
 
@@ -477,13 +492,6 @@ static void at91_irq_rx(struct net_device *dev, u32 reg_sr)
 }
 
 
 }
 
 
-static void at91_tx_timeout(struct net_device *dev)
-{
-       dev->stats.tx_errors++;
-       dev_dbg(ND2D(dev), "TX timeout!\n");
-}
-
-
 /*
  * theory of operation:
  *
 /*
  * theory of operation:
  *
@@ -526,8 +534,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
                at91_write(dev, AT91_IDR, 1 << mb);
 
                /*
                at91_write(dev, AT91_IDR, 1 << mb);
 
                /*
-                * only echo if mailbox signals us an transfer
-                * complete (MSR_MRDY). Otherwise it's an tansfer
+                * only echo if mailbox signals us a transfer
+                * complete (MSR_MRDY). Otherwise it's a tansfer
                 * abort. "can_bus_off()" takes care about the skbs
                 * parked in the echo queue.
                 */
                 * abort. "can_bus_off()" takes care about the skbs
                 * parked in the echo queue.
                 */
@@ -540,7 +548,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
 
        /*
         * restart queue if we don't have a wrap around but restart if
 
        /*
         * restart queue if we don't have a wrap around but restart if
-        * we get an TX int for the last can frame directly before a
+        * we get a TX int for the last can frame directly before a
         * wrap around.
         */
        if ((priv->tx_next & AT91_NEXT_MASK) != 0 ||
         * wrap around.
         */
        if ((priv->tx_next & AT91_NEXT_MASK) != 0 ||
@@ -599,11 +607,11 @@ static void at91_irq_err(struct net_device *dev, u32 reg_sr_masked)
        if (unlikely(reg_sr & AT91_IRQ_BOFF))
                new_state = CAN_STATE_BUS_OFF;
        else if (unlikely(reg_sr & AT91_IRQ_ERRP))
        if (unlikely(reg_sr & AT91_IRQ_BOFF))
                new_state = CAN_STATE_BUS_OFF;
        else if (unlikely(reg_sr & AT91_IRQ_ERRP))
-               new_state = CAN_STATE_BUS_PASSIVE;
+               new_state = CAN_STATE_ERROR_PASSIVE;
        else if (unlikely(reg_sr & AT91_IRQ_WARN))
        else if (unlikely(reg_sr & AT91_IRQ_WARN))
-               new_state = CAN_STATE_BUS_WARNING;
+               new_state = CAN_STATE_ERROR_WARNING;
        else if (likely(reg_sr & AT91_IRQ_ERRA))
        else if (likely(reg_sr & AT91_IRQ_ERRA))
-               new_state = CAN_STATE_ACTIVE;
+               new_state = CAN_STATE_ERROR_ACTIVE;
        else {
                BUG();  /* FIXME */
                return;
        else {
                BUG();  /* FIXME */
                return;
@@ -616,22 +624,22 @@ static void at91_irq_err(struct net_device *dev, u32 reg_sr_masked)
 
 
        switch (priv->can.state) {
 
 
        switch (priv->can.state) {
-       case CAN_STATE_ACTIVE:
+       case CAN_STATE_ERROR_ACTIVE:
                /*
                 * from: ACTIVE
                 * to  : BUS_WARNING, BUS_PASSIVE, BUS_OFF
                 * =>  : there was a warning int
                 */
                /*
                 * from: ACTIVE
                 * to  : BUS_WARNING, BUS_PASSIVE, BUS_OFF
                 * =>  : there was a warning int
                 */
-               if (new_state >= CAN_STATE_BUS_WARNING &&
+               if (new_state >= CAN_STATE_ERROR_WARNING &&
                    new_state <= CAN_STATE_BUS_OFF)
                        priv->can.can_stats.error_warning++;
                    new_state <= CAN_STATE_BUS_OFF)
                        priv->can.can_stats.error_warning++;
-       case CAN_STATE_BUS_WARNING:     /* fallthrough */
+       case CAN_STATE_ERROR_WARNING:   /* fallthrough */
                /*
                 * from: ACTIVE, BUS_WARNING
                 * to  : BUS_PASSIVE, BUS_OFF
                 * =>  : error passive int
                 */
                /*
                 * from: ACTIVE, BUS_WARNING
                 * to  : BUS_PASSIVE, BUS_OFF
                 * =>  : error passive int
                 */
-               if (new_state >= CAN_STATE_BUS_PASSIVE &&
+               if (new_state >= CAN_STATE_ERROR_PASSIVE &&
                    new_state <= CAN_STATE_BUS_OFF)
                        priv->can.can_stats.error_passive++;
                break;
                    new_state <= CAN_STATE_BUS_OFF)
                        priv->can.can_stats.error_passive++;
                break;
@@ -642,7 +650,7 @@ static void at91_irq_err(struct net_device *dev, u32 reg_sr_masked)
                 * success it leaves bus off. so we have to reenable
                 * the carrier.
                 */
                 * success it leaves bus off. so we have to reenable
                 * the carrier.
                 */
-               if (new_state <= CAN_STATE_BUS_PASSIVE)
+               if (new_state <= CAN_STATE_ERROR_PASSIVE)
                        netif_carrier_on(dev);
                break;
        default:
                        netif_carrier_on(dev);
                break;
        default:
@@ -652,18 +660,18 @@ static void at91_irq_err(struct net_device *dev, u32 reg_sr_masked)
 
        /* process state changes depending on the new state */
        switch (new_state) {
 
        /* process state changes depending on the new state */
        switch (new_state) {
-       case CAN_STATE_ACTIVE:
+       case CAN_STATE_ERROR_ACTIVE:
                /*
                 * actually we want to enable AT91_IRQ_WARN here, but
                 * it screws up the system under certain
                 * circumstances. so just enable AT91_IRQ_ERRP, thus
                 * the "fallthrough"
                 */
                /*
                 * actually we want to enable AT91_IRQ_WARN here, but
                 * it screws up the system under certain
                 * circumstances. so just enable AT91_IRQ_ERRP, thus
                 * the "fallthrough"
                 */
-       case CAN_STATE_BUS_WARNING:     /* fallthrough */
+       case CAN_STATE_ERROR_WARNING:   /* fallthrough */
                reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_BOFF;
                reg_ier = AT91_IRQ_ERRP;
                break;
                reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_BOFF;
                reg_ier = AT91_IRQ_ERRP;
                break;
-       case CAN_STATE_BUS_PASSIVE:
+       case CAN_STATE_ERROR_PASSIVE:
                reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_ERRP;
                reg_ier = AT91_IRQ_BOFF;
                break;
                reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_ERRP;
                reg_ier = AT91_IRQ_BOFF;
                break;
@@ -718,11 +726,11 @@ static void at91_irq_err(struct net_device *dev, u32 reg_sr_masked)
                cf->can_dlc = CAN_ERR_DLC;
 
                switch (new_state) {
                cf->can_dlc = CAN_ERR_DLC;
 
                switch (new_state) {
-               case CAN_STATE_BUS_WARNING:
-               case CAN_STATE_BUS_PASSIVE:
+               case CAN_STATE_ERROR_WARNING:
+               case CAN_STATE_ERROR_PASSIVE:
                        cf->can_id |= CAN_ERR_CRTL;
 
                        cf->can_id |= CAN_ERR_CRTL;
 
-                       if (new_state == CAN_STATE_BUS_WARNING)
+                       if (new_state == CAN_STATE_ERROR_WARNING)
                                cf->data[1] = (tec > rec) ?
                                        CAN_ERR_CRTL_TX_WARNING :
                                        CAN_ERR_CRTL_RX_WARNING;
                                cf->data[1] = (tec > rec) ?
                                        CAN_ERR_CRTL_TX_WARNING :
                                        CAN_ERR_CRTL_RX_WARNING;
@@ -829,32 +837,6 @@ static void at91_setup_mailboxes(struct net_device *dev)
        priv->tx_next = priv->tx_echo = priv->rx_bank = 0;
 }
 
        priv->tx_next = priv->tx_echo = priv->rx_bank = 0;
 }
 
-
-static struct net_device_stats *at91_get_stats(struct net_device *dev)
-{
-       struct at91_priv *priv = netdev_priv(dev);
-       u32 reg_ecr = at91_read(dev, AT91_ECR);
-
-       dev->stats.rx_errors = reg_ecr & 0xff;
-       dev->stats.tx_errors = reg_ecr >> 16;
-
-       /*
-        * here comes another one:
-        *
-        * the transmit error counter (TEC) has only a width of 8
-        * bits, so when the devices goes into BUS OFF (which is
-        * defined by a TEC > 255), the TEC in the chip shows "0". Not
-        * only that, it keeps accumulating errors, so they can vary
-        * between 0 and 255. We set TEC to 256 (hard) in BUS_OFF.
-        *
-        */
-       if (unlikely(priv->can.state == CAN_STATE_BUS_OFF))
-               dev->stats.tx_errors = 256;
-
-       return &dev->stats;
-}
-
-
 static int at91_set_bittiming(struct net_device *dev)
 {
        struct at91_priv *priv = netdev_priv(dev);
 static int at91_set_bittiming(struct net_device *dev)
 {
        struct at91_priv *priv = netdev_priv(dev);
@@ -869,7 +851,7 @@ static int at91_set_bittiming(struct net_device *dev)
                ((bt->phase_seg2 - 1) <<  0);
 
        dev_dbg(ND2D(dev), "writing AT91_BR: 0x%08x, can_sys_clock: %d\n",
                ((bt->phase_seg2 - 1) <<  0);
 
        dev_dbg(ND2D(dev), "writing AT91_BR: 0x%08x, can_sys_clock: %d\n",
-                 reg_br, priv->can.bittiming.clock);
+                 reg_br, priv->can.clock.freq);
        at91_write(dev, AT91_BR, reg_br);
 
        return 0;
        at91_write(dev, AT91_BR, reg_br);
 
        return 0;
@@ -897,7 +879,7 @@ static void at91_chip_start(struct net_device *dev)
        reg_mr = at91_read(dev, AT91_MR);
        at91_write(dev, AT91_MR, reg_mr | AT91_MR_AT91EN);
 
        reg_mr = at91_read(dev, AT91_MR);
        at91_write(dev, AT91_MR, reg_mr | AT91_MR_AT91EN);
 
-       priv->can.state = CAN_STATE_ACTIVE;
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
        /* Enable interrupts */
        reg_ier =
 
        /* Enable interrupts */
        reg_ier =
@@ -933,8 +915,8 @@ static int at91_open(struct net_device *dev)
 
        clk_enable(priv->clk);
 
 
        clk_enable(priv->clk);
 
-       /* determine and set bittime */
-       err = can_set_bittiming(dev);
+       /* check or determine and set bittime */
+       err = open_candev(dev);
        if (err)
                goto out;
 
        if (err)
                goto out;
 
@@ -942,7 +924,7 @@ static int at91_open(struct net_device *dev)
        if (request_irq(dev->irq, at91_irq, IRQF_SHARED,
                        dev->name, dev)) {
                err = -EAGAIN;
        if (request_irq(dev->irq, at91_irq, IRQF_SHARED,
                        dev->name, dev)) {
                err = -EAGAIN;
-               goto out;
+               goto out_close;
        }
 
        /* start chip and queuing */
        }
 
        /* start chip and queuing */
@@ -951,6 +933,8 @@ static int at91_open(struct net_device *dev)
 
        return 0;
 
 
        return 0;
 
+ out_close:
+       close_candev(dev);
  out:
        clk_disable(priv->clk);
 
  out:
        clk_disable(priv->clk);
 
@@ -971,20 +955,12 @@ static int at91_close(struct net_device *dev)
        free_irq(dev->irq, dev);
        clk_disable(priv->clk);
 
        free_irq(dev->irq, dev);
        clk_disable(priv->clk);
 
-       can_close_cleanup(dev);
+       close_candev(dev);
 
        return 0;
 }
 
 
 
        return 0;
 }
 
 
-static int at91_get_state(struct net_device *dev, u32 *state)
-{
-       struct at91_priv *priv = netdev_priv(dev);
-       *state = priv->can.state;
-       return 0;
-}
-
-
 static int at91_set_mode(struct net_device *dev, u32 _mode)
 {
        enum can_mode mode = _mode;
 static int at91_set_mode(struct net_device *dev, u32 _mode)
 {
        enum can_mode mode = _mode;
@@ -1005,17 +981,13 @@ static int at91_set_mode(struct net_device *dev, u32 _mode)
 }
 
 
 }
 
 
-static struct can_bittiming_const at91_bittiming_const = {
-       .tseg1_min = 4,
-       .tseg1_max = 16,
-       .tseg2_min = 2,
-       .tseg2_max = 8,
-       .sjw_max = 4,
-       .brp_min = 2,
-       .brp_max = 128,
-       .brp_inc = 1,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops at91_netdev_ops = {
+       .ndo_open       = at91_open,
+       .ndo_stop       = at91_close,
+       .ndo_start_xmit = at91_start_xmit,
 };
 };
-
+#endif
 
 static int __init at91_can_probe(struct platform_device *pdev)
 {
 
 static int __init at91_can_probe(struct platform_device *pdev)
 {
@@ -1059,22 +1031,23 @@ static int __init at91_can_probe(struct platform_device *pdev)
                goto exit_iounmap;
        }
 
                goto exit_iounmap;
        }
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops         = &at91_netdev_ops;
+#else
        dev->open               = at91_open;
        dev->stop               = at91_close;
        dev->hard_start_xmit    = at91_start_xmit;
        dev->open               = at91_open;
        dev->stop               = at91_close;
        dev->hard_start_xmit    = at91_start_xmit;
-       dev->tx_timeout = at91_tx_timeout;
-       dev->get_stats          = at91_get_stats;
+#endif
        dev->irq                = irq;
        dev->irq                = irq;
-       dev->base_addr          = (unsigned long)addr;
        dev->flags              |= IFF_ECHO;
 
        priv = netdev_priv(dev);
        dev->flags              |= IFF_ECHO;
 
        priv = netdev_priv(dev);
-       priv->can.bittiming.clock       = clk_get_rate(clk);
+       priv->can.clock.freq            = clk_get_rate(clk);
        priv->can.bittiming_const       = &at91_bittiming_const;
        priv->can.do_set_bittiming      = at91_set_bittiming;
        priv->can.bittiming_const       = &at91_bittiming_const;
        priv->can.do_set_bittiming      = at91_set_bittiming;
-       priv->can.do_get_state          = at91_get_state;
        priv->can.do_set_mode           = at91_set_mode;
        priv->clk                       = clk;
        priv->can.do_set_mode           = at91_set_mode;
        priv->clk                       = clk;
+       priv->reg_base                  = addr;
 
        priv->pdata             = pdev->dev.platform_data;
 
 
        priv->pdata             = pdev->dev.platform_data;
 
@@ -1088,8 +1061,8 @@ static int __init at91_can_probe(struct platform_device *pdev)
        }
 
 
        }
 
 
-       dev_info(&pdev->dev, "device registered (base_addr=%#lx, irq=%d)\n",
-                dev->base_addr, dev->irq);
+       dev_info(&pdev->dev, "device registered (reg_base=%#p, irq=%d)\n",
+                priv->reg_base, dev->irq);
 
        return 0;
 
 
        return 0;
 
@@ -1118,7 +1091,7 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
 
        free_netdev(dev);
 
 
        free_netdev(dev);
 
-       iounmap((void __iomem *)dev->base_addr);
+       iounmap(priv->reg_base);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, res->end - res->start + 1);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, res->end - res->start + 1);
diff --git a/kernel/2.6/drivers/net/can/cc770/Makefile b/kernel/2.6/drivers/net/can/cc770/Makefile
new file mode 100644 (file)
index 0000000..2d1da30
--- /dev/null
@@ -0,0 +1,26 @@
+#
+#  $Id: Makefile 443 2007-07-25 11:41:27Z hartkopp $
+#
+
+ifeq ($(KERNELRELEASE),)
+
+KERNELDIR := /lib/modules/$(shell uname -r)/build
+PWD       := $(shell pwd)
+TOPDIR    := $(PWD)/../../../..
+
+modules modules_install clean:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) $@ TOPDIR=$(TOPDIR)
+
+else
+
+-include $(TOPDIR)/Makefile.common
+
+obj-$(CONFIG_CAN_CC770) += cc770.o
+obj-$(CONFIG_CAN_CC770_ISA) += cc770_isa.o
+obj-$(CONFIG_CAN_CC770_OF_PLATFORM) += cc770_of_platform.o
+
+ifeq ($(CONFIG_CAN_DEBUG_DEVICES),y)
+       EXTRA_CFLAGS += -DDEBUG
+endif
+
+endif
diff --git a/kernel/2.6/drivers/net/can/cc770/cc770.c b/kernel/2.6/drivers/net/can/cc770/cc770.c
new file mode 100644 (file)
index 0000000..9fbc000
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+ * $Id:  $
+ *
+ * cc770.c - Bosch CC770 and Intel AN82527 network device driver
+ *
+ * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Derived from the old Socket-CAN i82527 driver:
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
+#include <socketcan/can/dev.h>
+
+#include "cc770.h"
+
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
+#define DRV_NAME  "cc770"
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver");
+
+/*
+ * The CC770 is a CAN controller from Bosch, which is 100% compatible
+ * with the AN82527 from Intel, but with "bugs" being fixed and some
+ * additional functionality, mainly:
+ *
+ * 1. RX and TX error counters are readable.
+ * 2. Support of silent (listen-only) mode.
+ * 3. Message object 15 can receive all types of frames, also RTR and EFF.
+ *
+ * Details are available from Bosch's "CC770_Product_Info_2007-01.pdf",
+ * which explains in detail the compatibility between the CC770 and the
+ * 82527. This driver use the additional functionality 3. on real CC770
+ * devices. Unfortunately, the CC770 does still not store the message
+ * identifier of received remote transmission request frames and
+ * therefore it's set to 0.
+ *
+ * The message objects 1..14 can be used for TX and RX while the message
+ * objects 15 is optimized for RX. It has a shadow register for reliable
+ * data receiption under heavy bus load. Therefore it makes sense to use
+ * this message object for the needed use case. The frame type (EFF/SFF)
+ * for the message object 15 can be defined via kernel module parameter
+ * "msgobj15_eff". If not equal 0, it will receive 29-bit EFF frames,
+ * otherwise 11 bit SFF messages.
+ */
+static int msgobj15_eff;
+module_param(msgobj15_eff, int, S_IRUGO);
+MODULE_PARM_DESC(msgobj15_eff, "Extended 29-bit frames for message object 15 "
+                "(default: 11-bit standard frames)");
+
+static int i82527_compat;
+module_param(i82527_compat, int, S_IRUGO);
+MODULE_PARM_DESC(i82527_compat, "Strict Intel 82527 comptibility mode "
+                "without using additional functions");
+
+/*
+ * This driver uses the last 5 message objects 11..15. The definitions
+ * and structure below allows to configure and assign them to the real
+ * message object.
+ */
+static unsigned char cc770_obj_flags[CC770_OBJ_MAX] = {
+       [CC770_OBJ_RX0]     = CC770_OBJ_FLAG_RX,
+       [CC770_OBJ_RX1]     = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_EFF,
+       [CC770_OBJ_RX_RTR0] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR,
+       [CC770_OBJ_RX_RTR1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR |
+                             CC770_OBJ_FLAG_EFF,
+       [CC770_OBJ_TX]      = 0,
+};
+
+static struct can_bittiming_const cc770_bittiming_const = {
+       .name = DRV_NAME,
+       .tseg1_min = 1,
+       .tseg1_max = 16,
+       .tseg2_min = 1,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 64,
+       .brp_inc = 1,
+};
+
+static inline int intid2obj(unsigned int intid)
+{
+       if (intid == 2)
+               return 0;
+       else
+               return MSGOBJ_LAST + 2 - intid;
+}
+
+static void enable_all_objs(const struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+       u8 msgcfg;
+       unsigned char obj_flags;
+       unsigned int o, mo;
+
+       for (o = 0; o <  CC770_OBJ_MAX; o++) {
+               obj_flags = priv->obj_flags[o];
+               mo = obj2msgobj(o);
+
+               if (obj_flags & CC770_OBJ_FLAG_RX) {
+                       /*
+                        * We don't need extra objects for RTR and EFF if
+                        * the additional CC770 functions are enabled.
+                        */
+                       if (priv->control_normal_mode & CTRL_EAF) {
+                               if (o > 0)
+                                       continue;
+                               dev_dbg(ND2D(dev), "Message object %d for "
+                                       "RX data, RTR, SFF and EFF\n", mo);
+                       } else {
+                               dev_dbg(ND2D(dev),
+                                       "Message object %d for RX %s %s\n", mo,
+                                       obj_flags & CC770_OBJ_FLAG_RTR ?
+                                       "RTR" : "data",
+                                       obj_flags & CC770_OBJ_FLAG_EFF ?
+                                         "EFF" : "SFF");
+                       }
+
+                       if (obj_flags & CC770_OBJ_FLAG_EFF)
+                               msgcfg = MSGCFG_XTD;
+                       else
+                               msgcfg = 0;
+                       if (obj_flags & CC770_OBJ_FLAG_RTR)
+                               msgcfg |= MSGCFG_DIR;
+
+                       cc770_write_reg(priv, msgobj[mo].config, msgcfg);
+                       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                                       MSGVAL_SET | TXIE_RES |
+                                       RXIE_SET | INTPND_RES);
+
+                       if (obj_flags & CC770_OBJ_FLAG_RTR)
+                               cc770_write_reg(priv, msgobj[mo].ctrl1,
+                                               NEWDAT_RES | CPUUPD_SET |
+                                               TXRQST_RES | RMTPND_RES);
+                       else
+                               cc770_write_reg(priv, msgobj[mo].ctrl1,
+                                               NEWDAT_RES | MSGLST_RES |
+                                               TXRQST_RES | RMTPND_RES);
+               } else {
+                       dev_dbg(ND2D(dev), "Message object %d for "
+                               "TX data, RTR, SFF and EFF\n", mo);
+
+                       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                                       RMTPND_RES | TXRQST_RES |
+                                       CPUUPD_RES | NEWDAT_RES);
+                       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                                       MSGVAL_RES | TXIE_RES |
+                                       RXIE_RES | INTPND_RES);
+               }
+       }
+}
+
+static void disable_all_objs(const struct cc770_priv *priv)
+{
+       int o, mo;
+
+       for (o = 0; o <  CC770_OBJ_MAX; o++) {
+               mo = obj2msgobj(o);
+
+               if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) {
+                       if (o > 0 &&
+                           priv->control_normal_mode & CTRL_EAF)
+                               continue;
+
+                       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                                       NEWDAT_RES | MSGLST_RES |
+                                       TXRQST_RES | RMTPND_RES);
+                       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                                       MSGVAL_RES | TXIE_RES |
+                                       RXIE_RES | INTPND_RES);
+               } else {
+                       /* Clear message object for send */
+                       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                                       RMTPND_RES | TXRQST_RES |
+                                       CPUUPD_RES | NEWDAT_RES);
+                       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                                       MSGVAL_RES | TXIE_RES |
+                                       RXIE_RES | INTPND_RES);
+               }
+       }
+}
+
+static void set_reset_mode(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       /* Enable configuration and puts chip in bus-off, disable interrupts */
+       cc770_write_reg(priv, control, CTRL_CCE | CTRL_INI);
+
+       priv->can.state = CAN_STATE_STOPPED;
+
+       /* Clear interrupts */
+       cc770_read_reg(priv, interrupt);
+
+       /* Clear status register */
+       cc770_write_reg(priv, status, 0);
+
+       /* Disable all used message objects */
+       disable_all_objs(priv);
+}
+
+static void set_normal_mode(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       /* Clear interrupts */
+       cc770_read_reg(priv, interrupt);
+
+       /* Clear status register and pre-set last error code */
+       cc770_write_reg(priv, status, STAT_LEC_MASK);
+
+       /* Enable all used message objects*/
+       enable_all_objs(dev);
+
+       /*
+        * Clear bus-off, interrupts only for errors,
+        * not for status change
+        */
+       cc770_write_reg(priv, control, priv->control_normal_mode);
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+static void chipset_init(struct cc770_priv *priv)
+{
+       int mo, id, data;
+
+       /* Enable configuration and put chip in bus-off, disable interrupts */
+       cc770_write_reg(priv, control, (CTRL_CCE | CTRL_INI));
+
+       /* Set CLKOUT divider and slew rates */
+       cc770_write_reg(priv, clkout, priv->clkout);
+
+       /* Configure CPU interface / CLKOUT enable */
+       cc770_write_reg(priv, cpu_interface, priv->cpu_interface | CPUIF_CEN);
+
+       /* Set bus configuration  */
+       cc770_write_reg(priv, bus_config, priv->bus_config);
+
+       /* Clear interrupts */
+       cc770_read_reg(priv, interrupt);
+
+       /* Clear status register */
+       cc770_write_reg(priv, status, 0);
+
+       /* Clear and invalidate message objects */
+       for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++) {
+               cc770_write_reg(priv, msgobj[mo].ctrl0,
+                               INTPND_UNC | RXIE_RES |
+                               TXIE_RES | MSGVAL_RES);
+               cc770_write_reg(priv, msgobj[mo].ctrl0,
+                               INTPND_RES | RXIE_RES |
+                               TXIE_RES | MSGVAL_RES);
+               cc770_write_reg(priv, msgobj[mo].ctrl1,
+                               NEWDAT_RES | MSGLST_RES |
+                               TXRQST_RES | RMTPND_RES);
+               for (data = 0; data < 8; data++)
+                       cc770_write_reg(priv, msgobj[mo].data[data], 0);
+               for (id = 0; id < 4; id++)
+                       cc770_write_reg(priv, msgobj[mo].id[id], 0);
+               cc770_write_reg(priv, msgobj[mo].config, 0);
+       }
+
+       /* Set all global ID masks to "don't care" */
+       cc770_write_reg(priv, global_mask_std[0], 0);
+       cc770_write_reg(priv, global_mask_std[1], 0);
+       cc770_write_reg(priv, global_mask_ext[0], 0);
+       cc770_write_reg(priv, global_mask_ext[1], 0);
+       cc770_write_reg(priv, global_mask_ext[2], 0);
+       cc770_write_reg(priv, global_mask_ext[3], 0);
+
+}
+
+static int cc770_probe_chip(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       /* Enable configuration, put chip in bus-off, disable ints */
+       cc770_write_reg(priv, control, CTRL_CCE | CTRL_EAF | CTRL_INI);
+       /* Configure cpu interface / CLKOUT disable */
+       cc770_write_reg(priv, cpu_interface, priv->cpu_interface);
+
+       /*
+        * Check if hardware reset is still inactive or maybe there
+        * is no chip in this address space
+        */
+       if (cc770_read_reg(priv, cpu_interface) & CPUIF_RST) {
+               dev_info(ND2D(dev), "probing @0x%p failed (reset)\n",
+                        priv->reg_base);
+               return 0;
+       }
+
+       /* Write and read back test pattern */
+       cc770_write_reg(priv, msgobj[1].data[1], 0x25);
+       cc770_write_reg(priv, msgobj[2].data[3], 0x52);
+       cc770_write_reg(priv, msgobj[10].data[6], 0xc3);
+       if ((cc770_read_reg(priv, msgobj[1].data[1]) != 0x25) ||
+           (cc770_read_reg(priv, msgobj[2].data[3]) != 0x52) ||
+           (cc770_read_reg(priv, msgobj[10].data[6]) != 0xc3)) {
+               dev_info(ND2D(dev), "probing @0x%p failed (pattern)\n",
+                        priv->reg_base);
+               return 0;
+       }
+
+       /* Check if this chip is a CC770 supporting additional functions */
+       if (cc770_read_reg(priv, control) & CTRL_EAF)
+               priv->control_normal_mode |= CTRL_EAF;
+
+       return 1;
+}
+
+static void cc770_start(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       /* leave reset mode */
+       if (priv->can.state != CAN_STATE_STOPPED)
+               set_reset_mode(dev);
+
+       /* leave reset mode */
+       set_normal_mode(dev);
+}
+
+static int cc770_set_mode(struct net_device *dev, enum can_mode mode)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       if (!priv->open_time)
+               return -EINVAL;
+
+       switch (mode) {
+       case CAN_MODE_START:
+               cc770_start(dev);
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int cc770_set_bittiming(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+       struct can_bittiming *bt = &priv->can.bittiming;
+       u8 btr0, btr1;
+
+       btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
+       btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
+               (((bt->phase_seg2 - 1) & 0x7) << 4);
+       if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+               btr1 |= 0x80;
+
+       dev_info(ND2D(dev),
+                "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
+
+       cc770_write_reg(priv, bit_timing_0, btr0);
+       cc770_write_reg(priv, bit_timing_1, btr1);
+
+       return 0;
+}
+
+static int cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
+       struct net_device_stats *stats = &dev->stats;
+#endif
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       unsigned int mo = obj2msgobj(CC770_OBJ_TX);
+       u8 dlc, rtr;
+       u32 id;
+       int i;
+
+       if ((cc770_read_reg(priv,
+                           msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
+               dev_err(ND2D(dev), "TX register is still occupied!\n");
+               return NETDEV_TX_BUSY;
+       }
+
+       netif_stop_queue(dev);
+
+       dlc = cf->can_dlc;
+       id = cf->can_id;
+       if (cf->can_id & CAN_RTR_FLAG)
+               rtr = 0;
+       else
+               rtr = MSGCFG_DIR;
+       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                       RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES);
+       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                       MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES);
+       if (id & CAN_EFF_FLAG) {
+               id &= CAN_EFF_MASK;
+               cc770_write_reg(priv, msgobj[mo].config,
+                               (dlc << 4) + rtr + MSGCFG_XTD);
+               cc770_write_reg(priv, msgobj[mo].id[3],
+                               (id << 3) & 0xFFU);
+               cc770_write_reg(priv, msgobj[mo].id[2],
+                               (id >> 5) & 0xFFU);
+               cc770_write_reg(priv, msgobj[mo].id[1],
+                               (id >> 13) & 0xFFU);
+               cc770_write_reg(priv, msgobj[mo].id[0],
+                               (id >> 21) & 0xFFU);
+       } else {
+               id &= CAN_SFF_MASK;
+               cc770_write_reg(priv, msgobj[mo].config,
+                               (dlc << 4) + rtr);
+               cc770_write_reg(priv, msgobj[mo].id[0],
+                               (id >> 3) & 0xFFU);
+               cc770_write_reg(priv, msgobj[mo].id[1],
+                               (id << 5) & 0xFFU);
+       }
+
+       dlc &= 0x0f;            /* restore length only */
+       for (i = 0; i < dlc; i++)
+               cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]);
+
+       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                       RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
+
+       stats->tx_bytes += dlc;
+       dev->trans_start = jiffies;
+
+       can_put_echo_skb(skb, dev, 0);
+
+       /*
+        * HM: We had some cases of repeated IRQs so make sure the
+        * INT is acknowledged I know it's already further up, but
+        * doing again fixed the issue
+        */
+       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                       MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
+
+       return NETDEV_TX_OK;
+}
+
+static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
+       struct net_device_stats *stats = &dev->stats;
+#endif
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       u8 config, dlc;
+       u32 id;
+       int i;
+
+       skb = dev_alloc_skb(sizeof(struct can_frame));
+       if (skb == NULL)
+               return;
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_CAN);
+
+       cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+       config = cc770_read_reg(priv, msgobj[mo].config);
+
+       if (ctrl1 & RMTPND_SET) {
+               /*
+                * Unfortunately, the chip does not store the real message
+                * identifier of the received remote transmission request
+                * frame. Therefore we set it to 0.
+                */
+               cf->can_id = CAN_RTR_FLAG;
+               if (config & MSGCFG_XTD)
+                       cf->can_id |= CAN_EFF_FLAG;
+               cf->can_dlc = 0;
+       } else {
+               if (config & MSGCFG_XTD) {
+                       id = cc770_read_reg(priv, msgobj[mo].id[3]);
+                       id |= cc770_read_reg(priv, msgobj[mo].id[2]) << 8;
+                       id |= cc770_read_reg(priv, msgobj[mo].id[1]) << 16;
+                       id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 24;
+                       id >>= 3;
+                       id |= CAN_EFF_FLAG;
+               } else {
+                       id = cc770_read_reg(priv, msgobj[mo].id[1]);
+                       id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 8;
+                       id >>= 5;
+               }
+
+               dlc = (config & 0xf0) >> 4; /* strip length code */
+               if (dlc > 8)
+                       dlc = 8;        /* limit count to 8 bytes */
+
+               cf->can_id = id;
+               cf->can_dlc = dlc;
+               for (i = 0; i < dlc; i++)
+                       cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]);
+       }
+       netif_rx(skb);
+
+       dev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+}
+
+static int cc770_err(struct net_device *dev, u8 status)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
+       struct net_device_stats *stats = &dev->stats;
+#endif
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       u8 lec;
+
+       dev_dbg(ND2D(dev), "status interrupt (%#x)\n", status);
+
+       skb = dev_alloc_skb(sizeof(struct can_frame));
+       if (skb == NULL)
+               return -ENOMEM;
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_CAN);
+       cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+       memset(cf, 0, sizeof(struct can_frame));
+       cf->can_id = CAN_ERR_FLAG;
+       cf->can_dlc = CAN_ERR_DLC;
+
+       if (status & STAT_BOFF) {
+               /* Disable interrupts */
+               cc770_write_reg(priv, control, CTRL_INI);
+               cf->can_id |= CAN_ERR_BUSOFF;
+               priv->can.state = CAN_STATE_BUS_OFF;
+               can_bus_off(dev);
+       } else if (status & STAT_WARN) {
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING;
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               priv->can.can_stats.error_warning++;
+       }
+
+       lec = status & STAT_LEC_MASK;
+       if (lec < 7 && lec > 0) {
+               if (lec == STAT_LEC_ACK) {
+                       cf->can_id |= CAN_ERR_ACK;
+               } else {
+                       cf->can_id |= CAN_ERR_PROT;
+                       switch (lec) {
+                       case STAT_LEC_STUFF:
+                               cf->data[2] |= CAN_ERR_PROT_STUFF;
+                               break;
+                       case STAT_LEC_FORM:
+                               cf->data[2] |= CAN_ERR_PROT_FORM;
+                               break;
+                       case STAT_LEC_BIT1:
+                               cf->data[2] |= CAN_ERR_PROT_BIT1;
+                               break;
+                       case STAT_LEC_BIT0:
+                               cf->data[2] |= CAN_ERR_PROT_BIT0;
+                               break;
+                       case STAT_LEC_CRC:
+                               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+                               break;
+                       }
+               }
+       }
+
+       netif_rx(skb);
+
+       dev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+
+       return 0;
+}
+
+static int cc770_status_interrupt(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+       u8 status;
+
+       status = cc770_read_reg(priv, status);
+       /* Reset the status register including RXOK and TXOK */
+       cc770_write_reg(priv, status, STAT_LEC_MASK);
+
+       if (status & (STAT_WARN | STAT_BOFF) ||
+           (status & STAT_LEC_MASK) != STAT_LEC_MASK) {
+               cc770_err(dev, status);
+               return status & STAT_BOFF;
+       }
+
+       return 0;
+}
+
+static void cc770_rx_interrupt(struct net_device *dev, unsigned int o)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
+       struct net_device_stats *stats = &dev->stats;
+#endif
+       unsigned int mo = obj2msgobj(o);
+       u8 ctrl1;
+
+       while (1) {
+               ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
+
+               if (!(ctrl1 & NEWDAT_SET))  {
+                       /* Check for RTR if additional functions are enabled */
+                       if (priv->control_normal_mode & CTRL_EAF) {
+                               if (!(cc770_read_reg(priv, msgobj[mo].ctrl0) &
+                                     INTPND_SET))
+                                       break;
+                       } else {
+                               break;
+                       }
+               }
+
+               if (ctrl1 & MSGLST_SET) {
+                       stats->rx_over_errors++;
+                       stats->rx_errors++;
+               }
+               if (mo < MSGOBJ_LAST)
+                       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                                       NEWDAT_RES | MSGLST_RES |
+                                       TXRQST_UNC | RMTPND_UNC);
+               cc770_rx(dev, mo, ctrl1);
+
+               cc770_write_reg(priv, msgobj[mo].ctrl0,
+                               MSGVAL_SET | TXIE_RES |
+                               RXIE_SET | INTPND_RES);
+               cc770_write_reg(priv, msgobj[mo].ctrl1,
+                               NEWDAT_RES | MSGLST_RES |
+                               TXRQST_RES | RMTPND_RES);
+       }
+}
+
+static void cc770_rtr_interrupt(struct net_device *dev, unsigned int o)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+       unsigned int mo = obj2msgobj(o);
+       u8 ctrl0, ctrl1;
+
+       while (1) {
+               ctrl0 = cc770_read_reg(priv, msgobj[mo].ctrl0);
+               if (!(ctrl0 & INTPND_SET))
+                       break;
+
+               ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
+               cc770_rx(dev, mo, ctrl1);
+
+               cc770_write_reg(priv, msgobj[mo].ctrl0,
+                               MSGVAL_SET | TXIE_RES |
+                               RXIE_SET | INTPND_RES);
+               cc770_write_reg(priv, msgobj[mo].ctrl1,
+                               NEWDAT_RES | CPUUPD_SET |
+                               TXRQST_RES | RMTPND_RES);
+       }
+}
+
+static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
+       struct net_device_stats *stats = &dev->stats;
+#endif
+       unsigned int mo = obj2msgobj(o);
+
+       /* Nothing more to send, switch off interrupts */
+       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                       MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
+       /*
+        * We had some cases of repeated IRQ so make sure the
+        * INT is acknowledged
+        */
+       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                       MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
+
+       stats->tx_packets++;
+       can_get_echo_skb(dev, 0);
+       netif_wake_queue(dev);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+irqreturn_t cc770_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t cc770_interrupt(int irq, void *dev_id)
+#endif
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct cc770_priv *priv = netdev_priv(dev);
+       u8 intid;
+       int o, n = 0;
+
+       /* Shared interrupts and IRQ off? */
+       if (priv->can.state == CAN_STATE_STOPPED)
+               return IRQ_NONE;
+
+       if (priv->pre_irq)
+               priv->pre_irq(priv);
+
+       while (n < CC770_MAX_IRQ) {
+               /* Read the highest pending interrupt request */
+               intid = cc770_read_reg(priv, interrupt);
+               if (!intid)
+                       break;
+               n++;
+
+               if (intid == 1) {
+                       /* Exit in case of bus-off */
+                       if (cc770_status_interrupt(dev))
+                               break;
+               } else {
+                       o = intid2obj(intid);
+
+                       if (o >= CC770_OBJ_MAX) {
+                               dev_err(ND2D(dev),
+                                       "Unexpected interrupt id %d\n", intid);
+                               continue;
+                       }
+
+                       if (priv->obj_flags[o] & CC770_OBJ_FLAG_RTR)
+                               cc770_rtr_interrupt(dev, o);
+                       else if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX)
+                               cc770_rx_interrupt(dev, o);
+                       else
+                               cc770_tx_interrupt(dev, o);
+               }
+       }
+
+       if (priv->post_irq)
+               priv->post_irq(priv);
+
+       if (n >= CC770_MAX_IRQ)
+               dev_dbg(ND2D(dev), "%d messages handled in ISR", n);
+
+       return (n) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int cc770_open(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+       int err;
+
+       /* set chip into reset mode */
+       set_reset_mode(dev);
+
+       /* common open */
+       err = open_candev(dev);
+       if (err)
+               return err;
+
+       err = request_irq(dev->irq, &cc770_interrupt, priv->irq_flags,
+                         dev->name, (void *)dev);
+       if (err) {
+               close_candev(dev);
+               return -EAGAIN;
+       }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       /* clear statistics */
+       memset(&priv->can.net_stats, 0, sizeof(priv->can.net_stats));
+#endif
+
+       /* init and start chip */
+       cc770_start(dev);
+       priv->open_time = jiffies;
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static int cc770_close(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       set_reset_mode(dev);
+
+       free_irq(dev->irq, (void *)dev);
+       close_candev(dev);
+
+       priv->open_time = 0;
+
+       return 0;
+}
+
+struct net_device *alloc_cc770dev(int sizeof_priv)
+{
+       struct net_device *dev;
+       struct cc770_priv *priv;
+
+       dev = alloc_candev(sizeof(struct cc770_priv) + sizeof_priv);
+       if (!dev)
+               return NULL;
+
+       priv = netdev_priv(dev);
+
+       priv->dev = dev;
+       priv->can.bittiming_const = &cc770_bittiming_const;
+       priv->can.do_set_bittiming = cc770_set_bittiming;
+       priv->can.do_set_mode = cc770_set_mode;
+
+       memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags));
+
+       if (sizeof_priv)
+               priv->priv = (void *)priv + sizeof(struct cc770_priv);
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_cc770dev);
+
+void free_cc770dev(struct net_device *dev)
+{
+       free_candev(dev);
+}
+EXPORT_SYMBOL_GPL(free_cc770dev);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops cc770_netdev_ops = {
+       .ndo_open               = cc770_open,
+       .ndo_stop               = cc770_close,
+       .ndo_start_xmit         = cc770_start_xmit,
+};
+#endif
+
+int register_cc770dev(struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       if (!cc770_probe_chip(dev))
+               return -ENODEV;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops = &cc770_netdev_ops;
+#else
+       dev->open = cc770_open;
+       dev->stop = cc770_close;
+       dev->hard_start_xmit = cc770_start_xmit;
+#endif
+
+       dev->flags |= IFF_ECHO; /* we support local echo */
+
+       /* Should we use additional functions? */
+       if (!i82527_compat && priv->control_normal_mode & CTRL_EAF) {
+               priv->control_normal_mode = CTRL_IE | CTRL_EAF | CTRL_EIE;
+               dev_dbg(ND2D(dev), "i82527 mode with additional functions\n");
+       } else {
+               priv->control_normal_mode = CTRL_IE | CTRL_EIE;
+               dev_dbg(ND2D(dev), "strict i82527 compatibility mode\n");
+       }
+
+       chipset_init(priv);
+       set_reset_mode(dev);
+
+       return register_candev(dev);
+}
+EXPORT_SYMBOL_GPL(register_cc770dev);
+
+void unregister_cc770dev(struct net_device *dev)
+{
+       set_reset_mode(dev);
+       unregister_candev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_cc770dev);
+
+static __init int cc770_init(void)
+{
+       if (msgobj15_eff) {
+               cc770_obj_flags[CC770_OBJ_RX0] |= CC770_OBJ_FLAG_EFF;
+               cc770_obj_flags[CC770_OBJ_RX1] &= ~CC770_OBJ_FLAG_EFF;
+       }
+
+       printk(KERN_INFO "%s CAN netdevice driver\n", DRV_NAME);
+
+       return 0;
+}
+
+module_init(cc770_init);
+
+static __exit void cc770_exit(void)
+{
+       printk(KERN_INFO "%s: driver removed\n", DRV_NAME);
+}
+module_exit(cc770_exit);
diff --git a/kernel/2.6/drivers/net/can/cc770/cc770.h b/kernel/2.6/drivers/net/can/cc770/cc770.h
new file mode 100644 (file)
index 0000000..1855c53
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * $Id:  $
+ *
+ * cc770.h - Bosch CC770 and Intel AN82527 network device driver
+ *
+ * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Derived from the old Socket-CAN i82527 driver:
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ */
+
+#ifndef CC770_DEV_H
+#define CC770_DEV_H
+
+#include <socketcan/can/dev.h>
+
+struct cc770_msgobj {
+       u8 ctrl0;
+       u8 ctrl1;
+       u8 id[4];
+       u8 config;
+       u8 data[8];
+       u8 dontuse;             /* padding */
+} __attribute__ ((packed));
+
+struct cc770_regs {
+       union {
+               struct cc770_msgobj msgobj[16]; /* Message object 1..15 */
+               struct {
+                       u8 control;             /* Control Register */
+                       u8 status;              /* Status Register */
+                       u8 cpu_interface;       /* CPU Interface Register */
+                       u8 dontuse1;
+                       u8 high_speed_read[2];  /* High Speed Read */
+                       u8 global_mask_std[2];  /* Standard Global Mask */
+                       u8 global_mask_ext[4];  /* Extended Global Mask */
+                       u8 msg15_mask[4];       /* Message 15 Mask */
+                       u8 dontuse2[15];
+                       u8 clkout;              /* Clock Out Register */
+                       u8 dontuse3[15];
+                       u8 bus_config;          /* Bus Configuration Register */
+                       u8 dontuse4[15];
+                       u8 bit_timing_0;        /* Bit Timing Register byte 0 */
+                       u8 dontuse5[15];
+                       u8 bit_timing_1;        /* Bit Timing Register byte 1 */
+                       u8 dontuse6[15];
+                       u8 interrupt;           /* Interrupt Register */
+                       u8 dontuse7[15];
+                       u8 rx_error_counter;    /* Receive Error Counter */
+                       u8 dontuse8[15];
+                       u8 tx_error_counter;    /* Transmit Error Counter */
+                       u8 dontuse9[31];
+                       u8 p1_conf;
+                       u8 dontuse10[15];
+                       u8 p2_conf;
+                       u8 dontuse11[15];
+                       u8 p1_in;
+                       u8 dontuse12[15];
+                       u8 p2_in;
+                       u8 dontuse13[15];
+                       u8 p1_out;
+                       u8 dontuse14[15];
+                       u8 p2_out;
+                       u8 dontuse15[15];
+                       u8 serial_reset_addr;
+               };
+       };
+} __attribute__ ((packed));
+
+/* Control Register (0x00) */
+#define CTRL_INI       0x01    /* Initialization */
+#define CTRL_IE                0x02    /* Interrupt Enable */
+#define CTRL_SIE       0x04    /* Status Interrupt Enable */
+#define CTRL_EIE       0x08    /* Error Interrupt Enable */
+#define CTRL_EAF       0x20    /* Enable additional functions */
+#define CTRL_CCE       0x40    /* Change Configuration Enable */
+
+/* Status Register (0x01) */
+#define STAT_LEC_STUFF 0x01    /* Stuff error */
+#define STAT_LEC_FORM  0x02    /* Form error */
+#define STAT_LEC_ACK   0x03    /* Acknowledgement error */
+#define STAT_LEC_BIT1  0x04    /* Bit1 error */
+#define STAT_LEC_BIT0  0x05    /* Bit0 error */
+#define STAT_LEC_CRC   0x06    /* CRC error */
+#define STAT_LEC_MASK  0x07    /* Last Error Code mask */
+#define STAT_TXOK      0x08    /* Transmit Message Successfully */
+#define STAT_RXOK      0x10    /* Receive Message Successfully */
+#define STAT_WAKE      0x20    /* Wake Up Status */
+#define STAT_WARN      0x40    /* Warning Status */
+#define STAT_BOFF      0x80    /* Bus Off Status */
+
+/* CPU Interface Register (0x02) */
+#define CPUIF_CEN      0x01    /* Clock Out Enable */
+#define CPUIF_MUX      0x04    /* Multiplex */
+#define CPUIF_SLP      0x08    /* Sleep */
+#define CPUIF_PWD      0x10    /* Power Down Mode */
+#define CPUIF_DMC      0x20    /* Divide Memory Clock */
+#define CPUIF_DSC      0x40    /* Divide System Clock */
+#define CPUIF_RST      0x80    /* Hardware Reset Status */
+
+/* Clock Out Register (0x1f) */
+#define CLKOUT_CD_MASK  0x0f   /* Clock Divider mask */
+#define CLKOUT_SL_MASK 0x30    /* Slew Rate mask */
+#define CLKOUT_SL_SHIFT        4
+
+/* Bus Configuration Register (0x2f) */
+#define BUSCFG_DR0     0x01    /* Disconnect RX0 Input / Select RX input */
+#define BUSCFG_DR1     0x02    /* Disconnect RX1 Input / Silent mode */
+#define BUSCFG_DT1     0x08    /* Disconnect TX1 Output */
+#define BUSCFG_POL     0x20    /* Polarity dominant or recessive */
+#define BUSCFG_CBY     0x40    /* Input Comparator Bypass */
+
+/* Message Control Register 0 (Base Address + 0x0) */
+#define INTPND_RES     0x01    /* No Interrupt pending */
+#define INTPND_SET     0x02    /* Interrupt pending */
+#define INTPND_UNC     0x03
+#define RXIE_RES       0x04    /* Receive Interrupt Disable */
+#define RXIE_SET       0x08    /* Receive Interrupt Enable */
+#define RXIE_UNC       0x0c
+#define TXIE_RES       0x10    /* Transmit Interrupt Disable */
+#define TXIE_SET       0x20    /* Transmit Interrupt Enable */
+#define TXIE_UNC       0x30
+#define MSGVAL_RES     0x40    /* Message Invalid */
+#define MSGVAL_SET     0x80    /* Message Valid */
+#define MSGVAL_UNC     0xc0
+
+/* Message Control Register 1 (Base Address + 0x01) */
+#define NEWDAT_RES     0x01    /* No New Data */
+#define NEWDAT_SET     0x02    /* New Data */
+#define NEWDAT_UNC     0x03
+#define MSGLST_RES     0x04    /* No Message Lost */
+#define MSGLST_SET     0x08    /* Message Lost */
+#define MSGLST_UNC     0x0c
+#define CPUUPD_RES     0x04    /* No CPU Updating */
+#define CPUUPD_SET     0x08    /* CPU Updating */
+#define CPUUPD_UNC     0x0c
+#define TXRQST_RES     0x10    /* No Transmission Request */
+#define TXRQST_SET     0x20    /* Transmission Request */
+#define TXRQST_UNC     0x30
+#define RMTPND_RES     0x40    /* No Remote Request Pending */
+#define RMTPND_SET     0x80    /* Remote Request Pending */
+#define RMTPND_UNC     0xc0
+
+/* Message Configuration Register (Base Address + 0x06) */
+#define MSGCFG_XTD     0x04    /* Extended Identifier */
+#define MSGCFG_DIR     0x08    /* Direction is Transmit */
+
+#define MSGOBJ_FIRST   1
+#define MSGOBJ_LAST    15
+
+#define CC770_IO_SIZE  0x100
+#define CC770_MAX_IRQ  20      /* max. number of interrupts handled in ISR */
+
+#define cc770_read_reg(priv, member)                                   \
+       priv->read_reg(priv, offsetof(struct cc770_regs, member))
+
+#define cc770_write_reg(priv, member, value)                           \
+       priv->write_reg(priv, offsetof(struct cc770_regs, member), value)
+
+/*
+ * Message objects and flags used by this driver
+ */
+#define CC770_OBJ_FLAG_RX  0x01
+#define CC770_OBJ_FLAG_RTR 0x02
+#define CC770_OBJ_FLAG_EFF 0x04
+
+enum {
+       CC770_OBJ_RX0 = 0,      /* for receiving normal messages */
+       CC770_OBJ_RX1,          /* for receiving normal messages */
+       CC770_OBJ_RX_RTR0,      /* for receiving remote transmission requests */
+       CC770_OBJ_RX_RTR1,      /* for receiving remote transmission requests */
+       CC770_OBJ_TX,           /* for sending messages */
+       CC770_OBJ_MAX
+};
+
+#define obj2msgobj(o)  (MSGOBJ_LAST - (o)) /* message object 11..15 */
+
+/*
+ * CC770 private data structure
+ */
+struct cc770_priv {
+       struct can_priv can;    /* must be the first member */
+       int open_time;
+       struct sk_buff *echo_skb;
+
+       /* the lower-layer is responsible for appropriate locking */
+       u8 (*read_reg)(const struct cc770_priv *priv, int reg);
+       void (*write_reg)(const struct cc770_priv *priv, int reg, u8 val);
+       void (*pre_irq)(const struct cc770_priv *priv);
+       void (*post_irq)(const struct cc770_priv *priv);
+
+       void *priv;             /* for board-specific data */
+       struct net_device *dev;
+
+       void __iomem *reg_base; /* ioremap'ed address to registers */
+       unsigned long irq_flags;        /* for request_irq() */
+
+       unsigned char obj_flags[CC770_OBJ_MAX];
+       u8 control_normal_mode; /* Control register for normal mode */
+       u8 cpu_interface;       /* CPU interface register */
+       u8 clkout;              /* Clock out register */
+       u8 bus_config;          /* Bus conffiguration register */
+};
+
+struct net_device *alloc_cc770dev(int sizeof_priv);
+void free_cc770dev(struct net_device *dev);
+int register_cc770dev(struct net_device *dev);
+void unregister_cc770dev(struct net_device *dev);
+
+#endif /* CC770_DEV_H */
diff --git a/kernel/2.6/drivers/net/can/cc770/cc770_isa.c b/kernel/2.6/drivers/net/can/cc770/cc770_isa.c
new file mode 100644 (file)
index 0000000..6a0f172
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#include <linux/io.h>
+#else
+#include <asm/io.h>
+#endif
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+
+#include "cc770.h"
+
+#define DRV_NAME "cc770_isa"
+
+#define MAXDEV 8
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#error This driver does not support Kernel versions < 2.6.16
+#endif
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the ISA bus");
+MODULE_LICENSE("GPL v2");
+
+#define CLK_DEFAULT    16000000        /* 16 MHz */
+#define BCR_DEFAULT    0x00
+#define COR_DEFAULT    0x00
+
+static unsigned long port[MAXDEV];
+static unsigned long mem[MAXDEV];
+static int __devinitdata irq[MAXDEV];
+static int __devinitdata clk[MAXDEV];
+static char __devinitdata cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static char __devinitdata bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static char __devinitdata cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static char __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+
+module_param_array(port, ulong, NULL, S_IRUGO);
+MODULE_PARM_DESC(port, "I/O port number");
+
+module_param_array(mem, ulong, NULL, S_IRUGO);
+MODULE_PARM_DESC(mem, "I/O memory address");
+
+module_param_array(indirect, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
+
+module_param_array(irq, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(irq, "IRQ number");
+
+module_param_array(clk, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(clk, "External oscillator clock frequency "
+                "(default=16000000 [16 MHz])");
+
+module_param_array(cir, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(cdr, "CPU interface register (default=0x40 [CPU_DSC])");
+
+module_param_array(bcr, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(ocr, "Bus configuration register (default=0x00)");
+
+module_param_array(cor, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(cor, "Clockout register (default=0x00)");
+
+#define CC770_IOSIZE          0x20
+#define CC770_IOSIZE_INDIRECT 0x02
+
+static u8 cc770_isa_mem_read_reg(const struct cc770_priv *priv, int reg)
+{
+       return readb(priv->reg_base + reg);
+}
+
+static void cc770_isa_mem_write_reg(const struct cc770_priv *priv,
+                                     int reg, u8 val)
+{
+       writeb(val, priv->reg_base + reg);
+}
+
+static u8 cc770_isa_port_read_reg(const struct cc770_priv *priv, int reg)
+{
+       return inb((unsigned long)priv->reg_base + reg);
+}
+
+static void cc770_isa_port_write_reg(const struct cc770_priv *priv,
+                                      int reg, u8 val)
+{
+       outb(val, (unsigned long)priv->reg_base + reg);
+}
+
+static u8 cc770_isa_port_read_reg_indirect(const struct cc770_priv *priv,
+                                            int reg)
+{
+       unsigned long base = (unsigned long)priv->reg_base;
+
+       outb(reg, base);
+       return inb(base + 1);
+}
+
+static void cc770_isa_port_write_reg_indirect(const struct cc770_priv *priv,
+                                               int reg, u8 val)
+{
+       unsigned long base = (unsigned long)priv->reg_base;
+
+       outb(reg, base);
+       outb(val, base + 1);
+}
+
+static int __devinit cc770_isa_match(struct device *pdev, unsigned int idx)
+{
+       if (port[idx] || mem[idx]) {
+               if (irq[idx])
+                       return 1;
+       } else if (idx)
+               return 0;
+
+       dev_err(pdev, "insufficient parameters supplied\n");
+       return 0;
+}
+
+static int __devinit cc770_isa_probe(struct device *pdev, unsigned int idx)
+{
+       struct net_device *dev;
+       struct cc770_priv *priv;
+       void __iomem *base = NULL;
+       int iosize = CC770_IOSIZE;
+       int err;
+       u32 clktmp;
+
+       if (mem[idx]) {
+               if (!request_mem_region(mem[idx], iosize, DRV_NAME)) {
+                       err = -EBUSY;
+                       goto exit;
+               }
+               base = ioremap_nocache(mem[idx], iosize);
+               if (!base) {
+                       err = -ENOMEM;
+                       goto exit_release;
+               }
+       } else {
+               if (indirect[idx] > 0 ||
+                   (indirect[idx] == -1 && indirect[0] > 0))
+                       iosize = CC770_IOSIZE_INDIRECT;
+               if (!request_region(port[idx], iosize, DRV_NAME)) {
+                       err = -EBUSY;
+                       goto exit;
+               }
+       }
+
+       dev = alloc_cc770dev(0);
+       if (!dev) {
+               err = -ENOMEM;
+               goto exit_unmap;
+       }
+       priv = netdev_priv(dev);
+
+       dev->irq = irq[idx];
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
+       if (mem[idx]) {
+               priv->reg_base = base;
+               dev->base_addr = mem[idx];
+               priv->read_reg = cc770_isa_mem_read_reg;
+               priv->write_reg = cc770_isa_mem_write_reg;
+       } else {
+               priv->reg_base = (void __iomem *)port[idx];
+               dev->base_addr = port[idx];
+
+               if (iosize == CC770_IOSIZE_INDIRECT) {
+                       priv->read_reg = cc770_isa_port_read_reg_indirect;
+                       priv->write_reg = cc770_isa_port_write_reg_indirect;
+               } else {
+                       priv->read_reg = cc770_isa_port_read_reg;
+                       priv->write_reg = cc770_isa_port_write_reg;
+               }
+       }
+
+       if (clk[idx])
+               clktmp = clk[idx];
+       else if (clk[0])
+               clktmp = clk[0];
+       else
+               clktmp = CLK_DEFAULT;
+       priv->can.clock.freq = clktmp;
+
+       if (cir[idx] != -1) {
+               priv->cpu_interface = cir[idx] & 0xff;
+       } else if (cir[0] != -1) {
+               priv->cpu_interface = cir[0] & 0xff;
+       } else {
+               /* The system clock may not exceed 10 MHz */
+               if (clktmp > 10000000) {
+                       priv->cpu_interface |= CPUIF_DSC;
+                       clktmp /= 2;
+               }
+               /* The memory clock may not exceed 8 MHz */
+               if (clktmp > 8000000)
+                       priv->cpu_interface |= CPUIF_DMC;
+       }
+
+       if (priv->cpu_interface & CPUIF_DSC)
+               priv->can.clock.freq /= 2;
+
+       if (bcr[idx] != -1)
+               priv->bus_config = bcr[idx] & 0xff;
+       else if (bcr[0] != -1)
+               priv->bus_config = bcr[0] & 0xff;
+       else
+               priv->bus_config = BCR_DEFAULT;
+
+       if (cor[idx] != -1)
+               priv->clkout = cor[idx] & 0xff;
+       else if (cor[0] != -1)
+               priv->clkout = cor[0] & 0xff;
+       else
+               priv->clkout = COR_DEFAULT;
+
+       dev_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, pdev);
+
+       err = register_cc770dev(dev);
+       if (err) {
+               dev_err(pdev, "registering %s failed (err=%d)\n",
+                       DRV_NAME, err);
+               goto exit_unmap;
+       }
+
+       dev_info(pdev, "%s device registered (reg_base=0x%p, irq=%d)\n",
+                DRV_NAME, priv->reg_base, dev->irq);
+       return 0;
+
+ exit_unmap:
+       if (mem[idx])
+               iounmap(base);
+ exit_release:
+       if (mem[idx])
+               release_mem_region(mem[idx], iosize);
+       else
+               release_region(port[idx], iosize);
+ exit:
+       return err;
+}
+
+static int __devexit cc770_isa_remove(struct device *pdev, unsigned int idx)
+{
+       struct net_device *dev = dev_get_drvdata(pdev);
+       struct cc770_priv *priv = netdev_priv(dev);
+
+       unregister_cc770dev(dev);
+       dev_set_drvdata(pdev, NULL);
+
+       if (mem[idx]) {
+               iounmap(priv->reg_base);
+               release_mem_region(mem[idx], CC770_IOSIZE);
+       } else {
+               if (priv->read_reg == cc770_isa_port_read_reg_indirect)
+                       release_region(port[idx], CC770_IOSIZE_INDIRECT);
+               else
+                       release_region(port[idx], CC770_IOSIZE);
+       }
+       free_cc770dev(dev);
+
+       return 0;
+}
+
+static struct isa_driver cc770_isa_driver = {
+       .match = cc770_isa_match,
+       .probe = cc770_isa_probe,
+       .remove = __devexit_p(cc770_isa_remove),
+       .driver = {
+               .name = DRV_NAME,
+       },
+};
+
+static int __init cc770_isa_init(void)
+{
+       int err = isa_register_driver(&cc770_isa_driver, MAXDEV);
+
+       if (!err)
+               printk(KERN_INFO
+                      "Legacy %s driver for max. %d devices registered\n",
+                      DRV_NAME, MAXDEV);
+       return err;
+}
+
+static void __exit cc770_isa_exit(void)
+{
+       isa_unregister_driver(&cc770_isa_driver);
+}
+
+module_init(cc770_isa_init);
+module_exit(cc770_isa_exit);
diff --git a/kernel/2.6/drivers/net/can/cc770/cc770_of_platform.c b/kernel/2.6/drivers/net/can/cc770/cc770_of_platform.c
new file mode 100644 (file)
index 0000000..7a8d937
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Driver for CC770 CAN controllers on the OpenFirmware platform bus
+ *
+ * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This is a generic driver for CC770 chips on the OpenFirmware platform
+ * bus found on embedded PowerPC systems. You need a CC770 CAN node
+ * definition in your flattened device tree source (DTS) file similar to:
+ *
+ *   can@3,100 {
+ *           compatible = "bosch,cc770";
+ *           reg = <3 0x100 0x80>;
+ *           interrupts = <2 0>;
+ *           interrupt-parent = <&mpic>;
+ *           bosch,external-clock-frequency = <16000000>;
+ *   };
+ *
+ * See "Documentation/powerpc/dts-bindings/can/cc770.txt" for further
+ * information.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+
+#include <linux/of_platform.h>
+#include <asm/prom.h>
+
+#include "cc770.h"
+
+#define DRV_NAME "cc770_of_platform"
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the OF platform bus");
+MODULE_LICENSE("GPL v2");
+
+#define CC770_OFP_CAN_CLOCK  16000000
+
+static u8 cc770_ofp_read_reg(const struct cc770_priv *priv, int reg)
+{
+       return in_8(priv->reg_base + reg);
+}
+
+static void cc770_ofp_write_reg(const struct cc770_priv *priv, int reg, u8 val)
+{
+       out_8(priv->reg_base + reg, val);
+}
+
+static int __devexit cc770_ofp_remove(struct of_device *ofdev)
+{
+       struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+       struct cc770_priv *priv = netdev_priv(dev);
+       struct resource res;
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+
+       unregister_cc770dev(dev);
+       iounmap(priv->reg_base);
+       /* irq_dispose_mapping(dev->irq);*/ /* will not work for shared IRQs */
+       free_cc770dev(dev);
+
+       of_address_to_resource(ofdev->node, 0, &res);
+       release_mem_region(res.start, resource_size(&res));
+
+       return 0;
+}
+
+static int __devinit cc770_ofp_probe(struct of_device *ofdev,
+                                    const struct of_device_id *id)
+{
+       struct device_node *np = ofdev->node;
+       struct net_device *dev;
+       struct cc770_priv *priv;
+       struct resource res;
+       const u32 *prop;
+       u32 clkext;
+       int err, irq, res_size, prop_size;
+       void __iomem *base;
+
+       err = of_address_to_resource(np, 0, &res);
+       if (err) {
+               dev_err(&ofdev->dev, "invalid address\n");
+               return err;
+       }
+
+       res_size = resource_size(&res);
+
+       if (!request_mem_region(res.start, res_size, DRV_NAME)) {
+               dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n",
+                       (unsigned long long)res.start,
+                       (unsigned long long)res.end);
+               return -EBUSY;
+       }
+
+       base = ioremap_nocache(res.start, res_size);
+       if (!base) {
+               dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n",
+                       (unsigned long long)res.start,
+                       (unsigned long long)res.end);
+               err = -ENOMEM;
+               goto exit_release_mem;
+       }
+
+       irq = irq_of_parse_and_map(np, 0);
+       if (irq == NO_IRQ) {
+               dev_err(&ofdev->dev, "no irq found\n");
+               err = -ENODEV;
+               goto exit_unmap_mem;
+       }
+
+       dev = alloc_cc770dev(0);
+       if (!dev) {
+               err = -ENOMEM;
+               goto exit_dispose_irq;
+       }
+
+       priv = netdev_priv(dev);
+
+       priv->read_reg = cc770_ofp_read_reg;
+       priv->write_reg = cc770_ofp_write_reg;
+
+       prop = of_get_property(np, "bosch,external-clock-frequency",
+                              &prop_size);
+       if (prop && (prop_size ==  sizeof(u32)))
+               clkext = *prop;
+       else
+               clkext = CC770_OFP_CAN_CLOCK; /* default */
+       priv->can.clock.freq = clkext;
+
+       /* The system clock may not exceed 10 MHz */
+       if (priv->can.clock.freq > 10000000) {
+               priv->cpu_interface |= CPUIF_DSC;
+               priv->can.clock.freq /= 2;
+       }
+
+       /* The memory clock may not exceed 8 MHz */
+       if (priv->can.clock.freq > 8000000)
+               priv->cpu_interface |= CPUIF_DMC;
+
+       if (of_get_property(np, "bosch,divide-memory-clock", NULL))
+               priv->cpu_interface |= CPUIF_DMC;
+       if (of_get_property(np, "bosch,iso-low-speed-mux", NULL))
+               priv->cpu_interface |= CPUIF_MUX;
+
+       if (of_get_property(np, "bosch,comperator-bypass", NULL))
+               priv->bus_config |= BUSCFG_CBY;
+       if (of_get_property(np, "bosch,disconnect-rx0-input", NULL))
+               priv->bus_config |= BUSCFG_DR0;
+       if (of_get_property(np, "bosch,disconnect-rx1-input", NULL))
+               priv->bus_config |= BUSCFG_DR1;
+       if (of_get_property(np, "bosch,disconnect-tx1-output", NULL))
+               priv->bus_config |= BUSCFG_DT1;
+       if (of_get_property(np, "bosch,polarity-dominant", NULL))
+               priv->bus_config |= BUSCFG_POL;
+
+       prop = of_get_property(np, "bosch,clock-out-frequency", &prop_size);
+       if (prop && (prop_size == sizeof(u32)) && *prop > 0) {
+               u32 cdv = clkext / *prop;
+               int slew;
+
+               if (cdv > 0 && cdv < 16) {
+                       priv->cpu_interface |= CPUIF_CEN;
+                       priv->clkout |= (cdv - 1) & CLKOUT_CD_MASK;
+
+                       prop = of_get_property(np, "bosch,slew-rate",
+                                              &prop_size);
+                       if (prop && (prop_size == sizeof(u32))) {
+                               slew = *prop;
+                       } else {
+                               /* Determine default slew rate */
+                               slew = (CLKOUT_SL_MASK >> CLKOUT_SL_SHIFT) -
+                                       ((cdv * clkext - 1) / 8000000);
+                               if (slew < 0)
+                                       slew = 0;
+                       }
+                       priv->clkout |= (slew << CLKOUT_SL_SHIFT) &
+                               CLKOUT_SL_MASK;
+               } else {
+                       dev_dbg(ND2D(dev), "invalid clock-out-frequency\n");
+               }
+
+       }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
+       priv->reg_base = base;
+
+       dev->irq = irq;
+
+       dev_info(&ofdev->dev,
+                "reg_base=0x%p irq=%d clock=%d cpu_interface=0x%02x "
+                "bus_config=0x%02x clkout=0x%02x\n",
+                priv->reg_base, dev->irq, priv->can.clock.freq,
+                priv->cpu_interface, priv->bus_config, priv->clkout);
+
+       dev_set_drvdata(&ofdev->dev, dev);
+       SET_NETDEV_DEV(dev, &ofdev->dev);
+
+       err = register_cc770dev(dev);
+       if (err) {
+               dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
+                       DRV_NAME, err);
+               goto exit_free_cc770;
+       }
+
+       return 0;
+
+exit_free_cc770:
+       free_cc770dev(dev);
+exit_dispose_irq:
+       /* irq_dispose_mapping(dev->irq);*/ /* will not work for shared IRQs */
+exit_unmap_mem:
+       iounmap(base);
+exit_release_mem:
+       release_mem_region(res.start, res_size);
+
+       return err;
+}
+
+static struct of_device_id __devinitdata cc770_ofp_table[] = {
+       {.compatible = "bosch,cc770"}, /* CC770 from Bosch */
+       {.compatible = "intc,82527"},  /* AN82527 from Intel CP */
+       {},
+};
+
+static struct of_platform_driver cc770_ofp_driver = {
+       .owner = THIS_MODULE,
+       .name = DRV_NAME,
+       .probe = cc770_ofp_probe,
+       .remove = __devexit_p(cc770_ofp_remove),
+       .match_table = cc770_ofp_table,
+};
+
+static int __init cc770_ofp_init(void)
+{
+       return of_register_platform_driver(&cc770_ofp_driver);
+}
+module_init(cc770_ofp_init);
+
+static void __exit cc770_ofp_exit(void)
+{
+       return of_unregister_platform_driver(&cc770_ofp_driver);
+};
+module_exit(cc770_ofp_exit);
index 0280a730577a67c21b494c9891785f462b3f1927..3a474a7540f011cc63fe857a073e844cc828b004 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
  * Copyright (C) 2006 Andrey Volkov, Varma Electronics
  *
  * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
  * Copyright (C) 2006 Andrey Volkov, Varma Electronics
- * Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
  */
 
 #include <linux/module.h>
  */
 
 #include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+
+#ifndef CONFIG_CAN_DEV_SYSFS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#error "CAN netlink interface not support by this kernel version"
+#endif
+#include <socketcan/can/netlink.h>
 #include <net/rtnetlink.h>
 #include <net/rtnetlink.h>
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+#error "CAN sysfs interface not support by this kernel version"
 #endif
 #endif
-
 #include "sysfs.h"
 #include "sysfs.h"
+#endif
 
 #define MOD_DESC "CAN device driver interface"
 
 
 #define MOD_DESC "CAN device driver interface"
 
@@ -46,6 +56,11 @@ MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
  * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
  * Copyright 2005      Stanislav Marek
  * email: pisa@cmp.felk.cvut.cz
  * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
  * Copyright 2005      Stanislav Marek
  * email: pisa@cmp.felk.cvut.cz
+ *
+ * Calculates proper bit-timing parameters for a specified bit-rate
+ * and sample-point, which can then be used to set the bit-timing
+ * registers of the CAN controller. You can find more information
+ * in the header file socketcan/can/netlink.h.
  */
 static int can_update_spt(const struct can_bittiming_const *btc,
                          int sampl_pt, int tseg, int *tseg1, int *tseg2)
  */
 static int can_update_spt(const struct can_bittiming_const *btc,
                          int sampl_pt, int tseg, int *tseg1, int *tseg2)
@@ -63,10 +78,9 @@ static int can_update_spt(const struct can_bittiming_const *btc,
        return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
 }
 
        return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
 }
 
-static int can_calc_bittiming(struct net_device *dev)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
 {
        struct can_priv *priv = netdev_priv(dev);
 {
        struct can_priv *priv = netdev_priv(dev);
-       struct can_bittiming *bt = &priv->bittiming;
        const struct can_bittiming_const *btc = priv->bittiming_const;
        long rate, best_rate = 0;
        long best_error = 1000000000, error = 0;
        const struct can_bittiming_const *btc = priv->bittiming_const;
        long rate, best_rate = 0;
        long best_error = 1000000000, error = 0;
@@ -95,12 +109,12 @@ static int can_calc_bittiming(struct net_device *dev)
             tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
                tsegall = 1 + tseg / 2;
                /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
             tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
                tsegall = 1 + tseg / 2;
                /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
-               brp = bt->clock / (tsegall * bt->bitrate) + tseg % 2;
+               brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
                /* chose brp step which is possible in system */
                brp = (brp / btc->brp_inc) * btc->brp_inc;
                if ((brp < btc->brp_min) || (brp > btc->brp_max))
                        continue;
                /* chose brp step which is possible in system */
                brp = (brp / btc->brp_inc) * btc->brp_inc;
                if ((brp < btc->brp_min) || (brp > btc->brp_max))
                        continue;
-               rate = bt->clock / (brp * tsegall);
+               rate = priv->clock.freq / (brp * tsegall);
                error = bt->bitrate - rate;
                /* tseg brp biterror */
                if (error < 0)
                error = bt->bitrate - rate;
                /* tseg brp biterror */
                if (error < 0)
@@ -129,7 +143,8 @@ static int can_calc_bittiming(struct net_device *dev)
                /* Error in one-tenth of a percent */
                error = (best_error * 1000) / bt->bitrate;
                if (error > CAN_CALC_MAX_ERROR) {
                /* Error in one-tenth of a percent */
                error = (best_error * 1000) / bt->bitrate;
                if (error > CAN_CALC_MAX_ERROR) {
-                       dev_err(ND2D(dev), "bitrate error %ld.%ld%% too high\n",
+                       dev_err(ND2D(dev),
+                               "bitrate error %ld.%ld%% too high\n",
                                error / 10, error % 10);
                        return -EDOM;
                } else {
                                error / 10, error % 10);
                        return -EDOM;
                } else {
@@ -141,49 +156,63 @@ static int can_calc_bittiming(struct net_device *dev)
        spt = can_update_spt(btc, sampl_pt, best_tseg, &tseg1, &tseg2);
 
        v64 = (u64)best_brp * 1000000000UL;
        spt = can_update_spt(btc, sampl_pt, best_tseg, &tseg1, &tseg2);
 
        v64 = (u64)best_brp * 1000000000UL;
-       do_div(v64, bt->clock);
+       do_div(v64, priv->clock.freq);
        bt->tq = (u32)v64;
        bt->prop_seg = tseg1 / 2;
        bt->phase_seg1 = tseg1 - bt->prop_seg;
        bt->phase_seg2 = tseg2;
        bt->sjw = 1;
        bt->brp = best_brp;
        bt->tq = (u32)v64;
        bt->prop_seg = tseg1 / 2;
        bt->phase_seg1 = tseg1 - bt->prop_seg;
        bt->phase_seg2 = tseg2;
        bt->sjw = 1;
        bt->brp = best_brp;
-
+#ifndef CONFIG_CAN_DEV_SYSFS
+       /* real bit-rate */
+       bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
+       /* real sample point */
+       bt->sample_point = spt;
+#endif
        return 0;
 }
 #else /* !CONFIG_CAN_CALC_BITTIMING */
        return 0;
 }
 #else /* !CONFIG_CAN_CALC_BITTIMING */
-static int can_calc_bittiming(struct net_device *dev)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
 {
        dev_err(ND2D(dev), "bit-timing calculation not available\n");
        return -EINVAL;
 }
 #endif /* CONFIG_CAN_CALC_BITTIMING */
 
 {
        dev_err(ND2D(dev), "bit-timing calculation not available\n");
        return -EINVAL;
 }
 #endif /* CONFIG_CAN_CALC_BITTIMING */
 
+
+#ifdef CONFIG_CAN_DEV_SYSFS
 int can_sample_point(struct can_bittiming *bt)
 {
        return ((bt->prop_seg + bt->phase_seg1 + 1) * 1000) /
                (bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1);
 }
 int can_sample_point(struct can_bittiming *bt)
 {
        return ((bt->prop_seg + bt->phase_seg1 + 1) * 1000) /
                (bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1);
 }
+#endif
 
 
-static int can_fixup_bittiming(struct net_device *dev)
+/*
+ * Checks the validity of the specified bit-timing parameters prop_seg,
+ * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
+ * prescaler value brp. You can find more information in the header
+ * file socketcan/can/netlink.h.
+ */
+static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
 {
        struct can_priv *priv = netdev_priv(dev);
 {
        struct can_priv *priv = netdev_priv(dev);
-       struct can_bittiming *bt = &priv->bittiming;
        const struct can_bittiming_const *btc = priv->bittiming_const;
        int tseg1, alltseg;
        const struct can_bittiming_const *btc = priv->bittiming_const;
        int tseg1, alltseg;
-       u32 bitrate;
        u64 brp64;
 
        if (!priv->bittiming_const)
                return -ENOTSUPP;
 
        tseg1 = bt->prop_seg + bt->phase_seg1;
        u64 brp64;
 
        if (!priv->bittiming_const)
                return -ENOTSUPP;
 
        tseg1 = bt->prop_seg + bt->phase_seg1;
+       if (!bt->sjw)
+               bt->sjw = 1;
        if (bt->sjw > btc->sjw_max ||
            tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
            bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
        if (bt->sjw > btc->sjw_max ||
            tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
            bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
-               return -EINVAL;
+               return -ERANGE;
 
 
-       brp64 = (u64)bt->clock * (u64)bt->tq;
+       brp64 = (u64)priv->clock.freq * (u64)bt->tq;
        if (btc->brp_inc > 1)
                do_div(brp64, btc->brp_inc);
        brp64 += 500000000UL - 1;
        if (btc->brp_inc > 1)
                do_div(brp64, btc->brp_inc);
        brp64 += 500000000UL - 1;
@@ -196,143 +225,33 @@ static int can_fixup_bittiming(struct net_device *dev)
                return -EINVAL;
 
        alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
                return -EINVAL;
 
        alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
-       bitrate = bt->clock / (bt->brp * alltseg);
-       bt->bitrate = bitrate;
+       bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
+       bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
 
        return 0;
 }
 
 
        return 0;
 }
 
-/*
- * Set CAN bit-timing for the device
- *
- * This functions should be called in the open function of the device
- * driver to determine, check and set appropriate bit-timing parameters.
- */
-int can_set_bittiming(struct net_device *dev)
+int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt)
 {
        struct can_priv *priv = netdev_priv(dev);
        int err;
 
 {
        struct can_priv *priv = netdev_priv(dev);
        int err;
 
-       /* Check if bit-timing parameters have been pre-defined */
-       if (!priv->bittiming.tq && !priv->bittiming.bitrate) {
-               dev_err(ND2D(dev), "bit-timing not yet defined\n");
-               return -EINVAL;
-       }
-
        /* Check if the CAN device has bit-timing parameters */
        if (priv->bittiming_const) {
 
        /* Check if the CAN device has bit-timing parameters */
        if (priv->bittiming_const) {
 
-               /* Check if bit-timing parameters have already been set */
-               if (priv->bittiming.tq && priv->bittiming.bitrate)
-                       return 0;
-
                /* Non-expert mode? Check if the bitrate has been pre-defined */
                /* Non-expert mode? Check if the bitrate has been pre-defined */
-               if (!priv->bittiming.tq)
+               if (!bt->tq)
                        /* Determine bit-timing parameters */
                        /* Determine bit-timing parameters */
-                       err = can_calc_bittiming(dev);
+                       err = can_calc_bittiming(dev, bt);
                else
                        /* Check bit-timing params and calculate proper brp */
                else
                        /* Check bit-timing params and calculate proper brp */
-                       err = can_fixup_bittiming(dev);
-               if (err)
-                       return err;
-       }
-
-       if (priv->do_set_bittiming) {
-               /* Finally, set the bit-timing registers */
-               err = priv->do_set_bittiming(dev);
+                       err = can_fixup_bittiming(dev, bt);
                if (err)
                        return err;
        }
 
        return 0;
 }
                if (err)
                        return err;
        }
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(can_set_bittiming);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-struct net_device_stats *can_get_stats(struct net_device *dev)
-{
-       struct can_priv *priv = netdev_priv(dev);
-
-       return &priv->net_stats;
-}
-EXPORT_SYMBOL_GPL(can_get_stats);
-#endif
-
-static void can_setup(struct net_device *dev)
-{
-       dev->type = ARPHRD_CAN;
-       dev->mtu = sizeof(struct can_frame);
-       dev->hard_header_len = 0;
-       dev->addr_len = 0;
-       dev->tx_queue_len = 10;
-
-       /* New-style flags. */
-       dev->flags = IFF_NOARP;
-       dev->features = NETIF_F_NO_CSUM;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-       dev->get_stats = can_get_stats;
-#endif
-}
-
-/*
- * Allocate and setup space for the CAN network device
- */
-struct net_device *alloc_candev(int sizeof_priv)
-{
-       struct net_device *dev;
-       struct can_priv *priv;
-
-       dev = alloc_netdev(sizeof_priv, "can%d", can_setup);
-       if (!dev)
-               return NULL;
-
-       priv = netdev_priv(dev);
-
-       priv->state = CAN_STATE_STOPPED;
-       spin_lock_init(&priv->irq_lock);
-
-       init_timer(&priv->timer);
-       priv->timer.expires = 0;
-
-       return dev;
-}
-EXPORT_SYMBOL_GPL(alloc_candev);
-
-/*
- * Allocate space of the CAN network device
- */
-void free_candev(struct net_device *dev)
-{
-       free_netdev(dev);
-}
-EXPORT_SYMBOL_GPL(free_candev);
-
-/*
- * Register the CAN network device
- */
-int register_candev(struct net_device *dev)
-{
-       int err;
-
-       err = register_netdev(dev);
-       if (err)
-               return err;
-
-       can_create_sysfs(dev);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(register_candev);
-
-/*
- * Unregister the CAN network device
- */
-void unregister_candev(struct net_device *dev)
-{
-       can_remove_sysfs(dev);
-       unregister_netdev(dev);
-}
-EXPORT_SYMBOL_GPL(unregister_candev);
 
 /*
  * Local echo of CAN messages
 
 /*
  * Local echo of CAN messages
@@ -344,7 +263,6 @@ EXPORT_SYMBOL_GPL(unregister_candev);
  * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
  * to perform the echo as a fallback solution.
  */
  * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
  * to perform the echo as a fallback solution.
  */
-
 static void can_flush_echo_skb(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
 static void can_flush_echo_skb(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
@@ -369,13 +287,14 @@ static void can_flush_echo_skb(struct net_device *dev)
  * Put the skb on the stack to be looped backed locally lateron
  *
  * The function is typically called in the start_xmit function
  * Put the skb on the stack to be looped backed locally lateron
  *
  * The function is typically called in the start_xmit function
- * of the device driver.
+ * of the device driver. The driver must protect access to
+ * priv->echo_skb, if necessary.
  */
 void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx)
 {
        struct can_priv *priv = netdev_priv(dev);
 
  */
 void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx)
 {
        struct can_priv *priv = netdev_priv(dev);
 
-       /* set flag whether this packet has to be looped back */
+       /* check flag whether this packet has to be looped back */
        if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
                kfree_skb(skb);
                return;
        if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
                kfree_skb(skb);
                return;
@@ -406,8 +325,8 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx)
                priv->echo_skb[idx] = skb;
        } else {
                /* locking problem with netif_stop_queue() ?? */
                priv->echo_skb[idx] = skb;
        } else {
                /* locking problem with netif_stop_queue() ?? */
-               printk(KERN_ERR "%s: %s: BUG! echo_skb is occupied!\n",
-                      dev->name, __func__);
+               dev_err(ND2D(dev), "%s: BUG! echo_skb is occupied!\n",
+                       __func__);
                kfree_skb(skb);
        }
 }
                kfree_skb(skb);
        }
 }
@@ -417,7 +336,8 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb);
  * Get the skb from the stack and loop it back locally
  *
  * The function is typically called when the TX done interrupt
  * Get the skb from the stack and loop it back locally
  *
  * The function is typically called when the TX done interrupt
- * is handled in the device driver.
+ * is handled in the device driver. The driver must protect
+ * access to priv->echo_skb, if necessary.
  */
 void can_get_echo_skb(struct net_device *dev, int idx)
 {
  */
 void can_get_echo_skb(struct net_device *dev, int idx)
 {
@@ -449,8 +369,9 @@ EXPORT_SYMBOL_GPL(can_free_echo_skb);
 /*
  * CAN device restart for bus-off recovery
  */
 /*
  * CAN device restart for bus-off recovery
  */
-int can_restart_now(struct net_device *dev)
+void can_restart(unsigned long data)
 {
 {
+       struct net_device *dev = (struct net_device *)data;
        struct can_priv *priv = netdev_priv(dev);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        struct net_device_stats *stats = can_get_stats(dev);
        struct can_priv *priv = netdev_priv(dev);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        struct net_device_stats *stats = can_get_stats(dev);
@@ -461,30 +382,20 @@ int can_restart_now(struct net_device *dev)
        struct can_frame *cf;
        int err;
 
        struct can_frame *cf;
        int err;
 
-       if (netif_carrier_ok(dev))
-               netif_carrier_off(dev);
-
-       /* Cancel restart in progress */
-       if (priv->timer.expires) {
-               del_timer(&priv->timer);
-               priv->timer.expires = 0; /* mark inactive timer */
-       }
+       BUG_ON(netif_carrier_ok(dev));
 
 
+       /*
+        * No synchronization needed because the device is bus-off and
+        * no messages can come in or go out.
+        */
        can_flush_echo_skb(dev);
 
        can_flush_echo_skb(dev);
 
-       err = priv->do_set_mode(dev, CAN_MODE_START);
-       if (err)
-               return err;
-
-       netif_carrier_on(dev);
-
-       dev_dbg(ND2D(dev), "restarted\n");
-       priv->can_stats.restarts++;
-
        /* send restart message upstream */
        skb = dev_alloc_skb(sizeof(struct can_frame));
        /* send restart message upstream */
        skb = dev_alloc_skb(sizeof(struct can_frame));
-       if (skb == NULL)
-               return -ENOMEM;
+       if (skb == NULL) {
+               err = -ENOMEM;
+               goto restart;
+       }
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
        cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
        cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
@@ -498,16 +409,35 @@ int can_restart_now(struct net_device *dev)
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
 
-       return 0;
+restart:
+       dev_dbg(ND2D(dev), "restarted\n");
+       priv->can_stats.restarts++;
+
+       /* Now restart the device */
+       err = priv->do_set_mode(dev, CAN_MODE_START);
+
+       netif_carrier_on(dev);
+       if (err)
+               dev_err(ND2D(dev), "Error %d during restart", err);
 }
 
 }
 
-static void can_restart_after(unsigned long data)
+int can_restart_now(struct net_device *dev)
 {
 {
-       struct net_device *dev = (struct net_device *)data;
        struct can_priv *priv = netdev_priv(dev);
 
        struct can_priv *priv = netdev_priv(dev);
 
-       priv->timer.expires = 0; /* mark inactive timer */
-       can_restart_now(dev);
+       /*
+        * A manual restart is only permitted if automatic restart is
+        * disabled and the device is in the bus-off state
+        */
+       if (priv->restart_ms)
+               return -EINVAL;
+       if (priv->state != CAN_STATE_BUS_OFF)
+               return -EBUSY;
+
+       /* Runs as soon as possible in the timer context */
+       mod_timer(&priv->restart_timer, jiffies);
+
+       return 0;
 }
 
 /*
 }
 
 /*
@@ -524,46 +454,325 @@ void can_bus_off(struct net_device *dev)
        dev_dbg(ND2D(dev), "bus-off\n");
 
        netif_carrier_off(dev);
        dev_dbg(ND2D(dev), "bus-off\n");
 
        netif_carrier_off(dev);
+       priv->can_stats.bus_off++;
 
 
-       if (priv->restart_ms > 0 && !priv->timer.expires) {
-
-               priv->timer.function = can_restart_after;
-               priv->timer.data = (unsigned long)dev;
-               priv->timer.expires =
-                       jiffies + (priv->restart_ms * HZ) / 1000;
-               add_timer(&priv->timer);
-       }
+       if (priv->restart_ms)
+               mod_timer(&priv->restart_timer,
+                         jiffies + (priv->restart_ms * HZ) / 1000);
 }
 EXPORT_SYMBOL_GPL(can_bus_off);
 
 }
 EXPORT_SYMBOL_GPL(can_bus_off);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+struct net_device_stats *can_get_stats(struct net_device *dev)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       return &priv->net_stats;
+}
+EXPORT_SYMBOL_GPL(can_get_stats);
+#endif
+
+static void can_setup(struct net_device *dev)
+{
+       dev->type = ARPHRD_CAN;
+       dev->mtu = sizeof(struct can_frame);
+       dev->hard_header_len = 0;
+       dev->addr_len = 0;
+       dev->tx_queue_len = 10;
+
+       /* New-style flags. */
+       dev->flags = IFF_NOARP;
+       dev->features = NETIF_F_NO_CSUM;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       dev->get_stats = can_get_stats;
+#endif
+}
+
+/*
+ * Allocate and setup space for the CAN network device
+ */
+struct net_device *alloc_candev(int sizeof_priv)
+{
+       struct net_device *dev;
+       struct can_priv *priv;
+
+       dev = alloc_netdev(sizeof_priv, "can%d", can_setup);
+       if (!dev)
+               return NULL;
+
+       priv = netdev_priv(dev);
+
+       priv->state = CAN_STATE_STOPPED;
+
+       init_timer(&priv->restart_timer);
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_candev);
+
+/*
+ * Free space of the CAN network device
+ */
+void free_candev(struct net_device *dev)
+{
+       free_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(free_candev);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+static inline void setup_timer(struct timer_list * timer,
+                               void (*function)(unsigned long),
+                               unsigned long data)
+{
+       timer->function = function;
+       timer->data = data;
+       init_timer(timer);
+}
+#endif
+
 /*
 /*
- * Cleanup function before the device gets closed.
+ * Common open function when the device gets opened.
  *
  *
- * This functions should be called in the close function of the device
+ * This function should be called in the open function of the device
  * driver.
  */
  * driver.
  */
-void can_close_cleanup(struct net_device *dev)
+int open_candev(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
 {
        struct can_priv *priv = netdev_priv(dev);
+#ifdef CONFIG_CAN_DEV_SYSFS
+       int err;
+#endif
+
+       if (!priv->bittiming.tq && !priv->bittiming.bitrate) {
+               dev_err(ND2D(dev), "bit-timing not yet defined\n");
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_CAN_DEV_SYSFS
+       err = can_get_bittiming(dev, &priv->bittiming);
+       if (err)
+               return err;
 
 
-       if (priv->timer.expires) {
-               del_timer(&priv->timer);
-               priv->timer.expires = 0;
+       if (priv->do_set_bittiming) {
+               /* Finally, set the bit-timing registers */
+               err = priv->do_set_bittiming(dev);
+               if (err)
+                       return err;
        }
        }
+#endif
 
 
+       setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(open_candev);
+
+/*
+ * Common close function for cleanup before the device gets closed.
+ *
+ * This function should be called in the close function of the device
+ * driver.
+ */
+void close_candev(struct net_device *dev)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       if (del_timer_sync(&priv->restart_timer))
+               dev_put(dev);
        can_flush_echo_skb(dev);
 }
        can_flush_echo_skb(dev);
 }
-EXPORT_SYMBOL_GPL(can_close_cleanup);
+EXPORT_SYMBOL_GPL(close_candev);
+
+#ifndef CONFIG_CAN_DEV_SYSFS
+/*
+ * CAN netlink interface
+ */
+static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
+       [IFLA_CAN_STATE]        = { .type = NLA_U32 },
+       [IFLA_CAN_CTRLMODE]     = { .len = sizeof(struct can_ctrlmode) },
+       [IFLA_CAN_RESTART_MS]   = { .type = NLA_U32 },
+       [IFLA_CAN_RESTART]      = { .type = NLA_U32 },
+       [IFLA_CAN_BITTIMING]    = { .len = sizeof(struct can_bittiming) },
+       [IFLA_CAN_BITTIMING_CONST]
+                               = { .len = sizeof(struct can_bittiming_const) },
+       [IFLA_CAN_CLOCK]        = { .len = sizeof(struct can_clock) },
+};
+
+static int can_changelink(struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[])
+{
+       struct can_priv *priv = netdev_priv(dev);
+       int err;
+
+       /* We need synchronization with dev->stop() */
+       ASSERT_RTNL();
+
+       if (data[IFLA_CAN_CTRLMODE]) {
+               struct can_ctrlmode *cm;
+
+               /* Do not allow changing controller mode while running */
+               if (dev->flags & IFF_UP)
+                       return -EBUSY;
+               cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+               priv->ctrlmode &= ~cm->mask;
+               priv->ctrlmode |= cm->flags;
+       }
+
+       if (data[IFLA_CAN_BITTIMING]) {
+               struct can_bittiming bt;
+
+               /* Do not allow changing bittiming while running */
+               if (dev->flags & IFF_UP)
+                       return -EBUSY;
+               memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
+               if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq))
+                       return -EINVAL;
+               err = can_get_bittiming(dev, &bt);
+               if (err)
+                       return err;
+               memcpy(&priv->bittiming, &bt, sizeof(bt));
+
+               if (priv->do_set_bittiming) {
+                       /* Finally, set the bit-timing registers */
+                       err = priv->do_set_bittiming(dev);
+                       if (err)
+                               return err;
+               }
+       }
+
+       if (data[IFLA_CAN_RESTART_MS]) {
+               /* Do not allow changing restart delay while running */
+               if (dev->flags & IFF_UP)
+                       return -EBUSY;
+               priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
+       }
+
+       if (data[IFLA_CAN_RESTART]) {
+               /* Do not allow a restart while not running */
+               if (!(dev->flags & IFF_UP))
+                       return -EINVAL;
+               err = can_restart_now(dev);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct can_priv *priv = netdev_priv(dev);
+       struct can_ctrlmode cm = {.flags = priv->ctrlmode};
+       enum can_state state = priv->state;
+
+       if (priv->do_get_state)
+               priv->do_get_state(dev, &state);
+       NLA_PUT_U32(skb, IFLA_CAN_STATE, state);
+       NLA_PUT(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm);
+       NLA_PUT_U32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms);
+       NLA_PUT(skb, IFLA_CAN_BITTIMING,
+               sizeof(priv->bittiming), &priv->bittiming);
+       NLA_PUT(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock);
+       if (priv->bittiming_const)
+               NLA_PUT(skb, IFLA_CAN_BITTIMING_CONST,
+                       sizeof(*priv->bittiming_const), priv->bittiming_const);
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       NLA_PUT(skb, IFLA_INFO_XSTATS,
+               sizeof(priv->can_stats), &priv->can_stats);
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static int can_newlink(struct net_device *dev,
+                      struct nlattr *tb[], struct nlattr *data[])
+{
+       return -EOPNOTSUPP;
+}
+
+static struct rtnl_link_ops can_link_ops __read_mostly = {
+       .kind           = "can",
+       .maxtype        = IFLA_CAN_MAX,
+       .policy         = can_policy,
+       .setup          = can_setup,
+       .newlink        = can_newlink,
+       .changelink     = can_changelink,
+       .fill_info      = can_fill_info,
+       .fill_xstats    = can_fill_xstats,
+};
+
+#endif /* !CONFIG_CAN_DEV_SYSFS */
+
+/*
+ * Register the CAN network device
+ */
+int register_candev(struct net_device *dev)
+{
+#ifdef CONFIG_CAN_DEV_SYSFS
+       int err;
+
+       err = register_netdev(dev);
+       if (!err)
+               can_create_sysfs(dev);
+
+       return err;
+#else
+       dev->rtnl_link_ops = &can_link_ops;
+       return register_netdev(dev);
+#endif
+}
+EXPORT_SYMBOL_GPL(register_candev);
+
+/*
+ * Unregister the CAN network device
+ */
+void unregister_candev(struct net_device *dev)
+{
+#ifdef CONFIG_CAN_DEV_SYSFS
+       can_remove_sysfs(dev);
+#endif
+       unregister_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_candev);
 
 static __init int can_dev_init(void)
 {
 
 static __init int can_dev_init(void)
 {
-       printk(KERN_INFO MOD_DESC "\n");
+#ifndef CONFIG_CAN_DEV_SYSFS
+       int err;
+
+       err = rtnl_link_register(&can_link_ops);
+       if (!err)
+               printk(KERN_INFO MOD_DESC "\n");
+
+       return err;
+#else
+       printk(KERN_INFO MOD_DESC " using the deprecated SYSFS interface\n");
 
        return 0;
 
        return 0;
+#endif
 }
 module_init(can_dev_init);
 
 static __exit void can_dev_exit(void)
 {
 }
 module_init(can_dev_init);
 
 static __exit void can_dev_exit(void)
 {
+#ifndef CONFIG_CAN_DEV_SYSFS
+       rtnl_link_unregister(&can_link_ops);
+#endif
 }
 module_exit(can_dev_exit);
 }
 module_exit(can_dev_exit);
+
+#ifndef CONFIG_CAN_DEV_SYSFS
+MODULE_ALIAS_RTNL_LINK("can");
+#endif
index 3d0c798b819374debad24bd0c2725cca93ad00fd..258122c9f23fe0fb14b1dc2f36d0c2af66073be5 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/byteorder/generic.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/byteorder/generic.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-#include <linux/can.h>
-#include <linux/can/error.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/error.h>
+#include <socketcan/can/dev.h>
 
 #define DRV_NAME "esd_pci331"
 
 
 #define DRV_NAME "esd_pci331"
 
@@ -47,8 +48,14 @@ MODULE_DESCRIPTION("Socket-CAN driver for the esd 331 CAN cards");
 MODULE_DEVICE_TABLE(pci, esd331_pci_tbl);
 MODULE_SUPPORTED_DEVICE("esd CAN-PCI/331, CAN-CPCI/331, CAN-PMC/331");
 
 MODULE_DEVICE_TABLE(pci, esd331_pci_tbl);
 MODULE_SUPPORTED_DEVICE("esd CAN-PCI/331, CAN-CPCI/331, CAN-PMC/331");
 
+#ifndef PCI_DEVICE_ID_PLX_9030
+# define PCI_DEVICE_ID_PLX_9030        0x9030
+#endif
 #ifndef PCI_DEVICE_ID_PLX_9050
 #ifndef PCI_DEVICE_ID_PLX_9050
-# define PCI_DEVICE_ID_PLX_9050 0x9050
+# define PCI_DEVICE_ID_PLX_9050        0x9050
+#endif
+#ifndef PCI_VENDOR_ID_ESDGMBH
+#define PCI_VENDOR_ID_ESDGMBH   0x12fe
 #endif
 
 #define ESD_PCI_SUB_SYS_ID_PCI331 0x0001
 #endif
 
 #define ESD_PCI_SUB_SYS_ID_PCI331 0x0001
@@ -434,7 +441,11 @@ static int esd331_create_err_frame(struct net_device *dev, canid_t idflags,
        if (unlikely(skb == NULL))
                return -ENOMEM;
 
        if (unlikely(skb == NULL))
                return -ENOMEM;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       stats = can_get_stats(dev);
+#else
        stats = &dev->stats;
        stats = &dev->stats;
+#endif
 
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
 
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
@@ -457,7 +468,11 @@ static int esd331_create_err_frame(struct net_device *dev, canid_t idflags,
 static void esd331_irq_rx(struct net_device *dev, struct esd331_can_msg *msg,
                                int eff)
 {
 static void esd331_irq_rx(struct net_device *dev, struct esd331_can_msg *msg,
                                int eff)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
        struct net_device_stats *stats = &dev->stats;
        struct net_device_stats *stats = &dev->stats;
+#endif
        struct can_frame *cfrm;
        struct sk_buff *skb;
        int i;
        struct can_frame *cfrm;
        struct sk_buff *skb;
        int i;
@@ -510,14 +525,14 @@ static void esd331_handle_errmsg(struct net_device *dev,
        switch (msg->data[1]) {
        case ESD331_ERR_OK:
                if (priv->can.state != CAN_STATE_STOPPED)
        switch (msg->data[1]) {
        case ESD331_ERR_OK:
                if (priv->can.state != CAN_STATE_STOPPED)
-                       priv->can.state = CAN_STATE_ACTIVE;
+                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
                break;
 
        case ESD331_ERR_WARN:
                break;
 
        case ESD331_ERR_WARN:
-               if ((priv->can.state != CAN_STATE_BUS_WARNING)
+               if ((priv->can.state != CAN_STATE_ERROR_WARNING)
                                && (priv->can.state != CAN_STATE_STOPPED)) {
                        priv->can.can_stats.error_warning++;
                                && (priv->can.state != CAN_STATE_STOPPED)) {
                        priv->can.can_stats.error_warning++;
-                       priv->can.state = CAN_STATE_BUS_WARNING;
+                       priv->can.state = CAN_STATE_ERROR_WARNING;
 
                        /* might be RX warning, too... */
                        esd331_create_err_frame(dev, CAN_ERR_CRTL,
 
                        /* might be RX warning, too... */
                        esd331_create_err_frame(dev, CAN_ERR_CRTL,
@@ -543,6 +558,7 @@ static void esd331_handle_errmsg(struct net_device *dev,
 
 static void esd331_handle_messages(struct esd331_pci *board)
 {
 
 static void esd331_handle_messages(struct esd331_pci *board)
 {
+       struct net_device *dev;
        struct esd331_priv *priv;
        struct net_device_stats *stats;
        struct esd331_can_msg msg;
        struct esd331_priv *priv;
        struct net_device_stats *stats;
        struct esd331_can_msg msg;
@@ -553,37 +569,41 @@ static void esd331_handle_messages(struct esd331_pci *board)
                                || (board->dev[msg.net] == NULL)))
                        continue;
 
                                || (board->dev[msg.net] == NULL)))
                        continue;
 
-               priv = netdev_priv(board->dev[msg.net]);
+               dev = board->dev[msg.net];
+               priv = netdev_priv(dev);
                if (priv->can.state == CAN_STATE_STOPPED)
                        continue;
 
                if (priv->can.state == CAN_STATE_STOPPED)
                        continue;
 
-               stats = &board->dev[msg.net]->stats;
-
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+               stats = can_get_stats(dev);
+#else
+               stats = &dev->stats;
+#endif
                switch (msg.cmmd) {
 
                case ESD331_I20_BCAN:
                case ESD331_I20_EX_BCAN:
                switch (msg.cmmd) {
 
                case ESD331_I20_BCAN:
                case ESD331_I20_EX_BCAN:
-                       esd331_irq_rx(board->dev[msg.net], &msg,
+                       esd331_irq_rx(dev, &msg,
                                        (msg.cmmd == ESD331_I20_EX_BCAN));
                        break;
 
                case ESD331_I20_TXDONE:
                case ESD331_I20_EX_TXDONE:
                        stats->tx_packets++;
                                        (msg.cmmd == ESD331_I20_EX_BCAN));
                        break;
 
                case ESD331_I20_TXDONE:
                case ESD331_I20_EX_TXDONE:
                        stats->tx_packets++;
-                       can_get_echo_skb(board->dev[msg.net], 0);
-                       netif_wake_queue(board->dev[msg.net]);
+                       can_get_echo_skb(dev, 0);
+                       netif_wake_queue(dev);
                        break;
 
                case ESD331_I20_TXTOUT:
                case ESD331_I20_EX_TXTOUT:
                        stats->tx_errors++;
                        stats->tx_dropped++;
                        break;
 
                case ESD331_I20_TXTOUT:
                case ESD331_I20_EX_TXTOUT:
                        stats->tx_errors++;
                        stats->tx_dropped++;
-                       can_free_echo_skb(board->dev[msg.net], 0);
-                       netif_wake_queue(board->dev[msg.net]);
+                       can_free_echo_skb(dev, 0);
+                       netif_wake_queue(dev);
                        break;
 
                case ESD331_I20_ERROR:
                        break;
 
                case ESD331_I20_ERROR:
-                       esd331_handle_errmsg(board->dev[msg.net], &msg);
+                       esd331_handle_errmsg(dev, &msg);
                        break;
 
                default:
                        break;
 
                default:
@@ -627,7 +647,6 @@ irqreturn_t esd331_interrupt(int irq, void *dev_id)
 
        return IRQ_HANDLED;
 }
 
        return IRQ_HANDLED;
 }
-EXPORT_SYMBOL_GPL(esd331_interrupt);
 
 /* also enables interrupt when no other net on card is openened yet */
 static int esd331_open(struct net_device *dev)
 
 /* also enables interrupt when no other net on card is openened yet */
 static int esd331_open(struct net_device *dev)
@@ -635,7 +654,7 @@ static int esd331_open(struct net_device *dev)
        struct esd331_priv *priv = netdev_priv(dev);
        int err;
 
        struct esd331_priv *priv = netdev_priv(dev);
        int err;
 
-       err = can_set_bittiming(dev);
+       err = open_candev(dev);
        if (err)
                return err;
 
        if (err)
                return err;
 
@@ -646,7 +665,7 @@ static int esd331_open(struct net_device *dev)
        if (esd331_all_nets_stopped(priv->board))
                esd331_enable_irq(priv->board->conf_addr);
 
        if (esd331_all_nets_stopped(priv->board))
                esd331_enable_irq(priv->board->conf_addr);
 
-       priv->can.state = CAN_STATE_ACTIVE;
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
        netif_start_queue(dev);
 
        return 0;
        netif_start_queue(dev);
 
        return 0;
@@ -659,7 +678,7 @@ static int esd331_close(struct net_device *dev)
 
        priv->can.state = CAN_STATE_STOPPED;
        netif_stop_queue(dev);
 
        priv->can.state = CAN_STATE_STOPPED;
        netif_stop_queue(dev);
-       can_close_cleanup(dev);
+       close_candev(dev);
 
        if (esd331_all_nets_stopped(priv->board))
                esd331_disable_irq(priv->board->conf_addr);
 
        if (esd331_all_nets_stopped(priv->board))
                esd331_disable_irq(priv->board->conf_addr);
@@ -670,7 +689,11 @@ static int esd331_close(struct net_device *dev)
 static int esd331_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct esd331_priv *priv = netdev_priv(dev);
 static int esd331_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct esd331_priv *priv = netdev_priv(dev);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats *stats = can_get_stats(dev);
+#else
        struct net_device_stats *stats = &dev->stats;
        struct net_device_stats *stats = &dev->stats;
+#endif
        struct can_frame *cf = (struct can_frame *)skb->data;
        int err;
 
        struct can_frame *cf = (struct can_frame *)skb->data;
        int err;
 
@@ -725,7 +748,7 @@ static int esd331_set_mode(struct net_device *dev, enum can_mode mode)
 
        switch (mode) {
        case CAN_MODE_START:
 
        switch (mode) {
        case CAN_MODE_START:
-               priv->can.state = CAN_STATE_ACTIVE;
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
 
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
 
@@ -772,6 +795,7 @@ static struct net_device *__devinit esd331_pci_add_chan(struct pci_dev *pdev,
 #endif
 
        dev->irq = pdev->irq;
 #endif
 
        dev->irq = pdev->irq;
+       /* Set and enable PCI interrupts */
        dev->flags |= IFF_ECHO;
 
        priv->can.do_set_bittiming = esd331_set_bittiming;
        dev->flags |= IFF_ECHO;
 
        priv->can.do_set_bittiming = esd331_set_bittiming;
index 1dcda35e0d7da375879695570b6d9abfc6b6832a..bde7c53b85ae2ea970e635e1deb3d916f5f8ea76 100644 (file)
@@ -1,5 +1,4 @@
 /*
 /*
- *
  * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
  *
  * MCP2510 support and bug fixes by Christian Pellegrin
  * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
  *
  * MCP2510 support and bug fixes by Christian Pellegrin
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
+#include <socketcan/can.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
-#include <linux/can/dev.h>
-#include <linux/can/core.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/core.h>
 #include <linux/if_arp.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/if_arp.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
-#include <linux/can/platform/mcp251x.h>
+#include <socketcan/can/platform/mcp251x.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+#error This driver does not support Kernel versions < 2.6.22
+#endif
 
 /* SPI interface instruction set */
 
 /* SPI interface instruction set */
-#define INSTRUCTION_WRITE              0x02
-#define INSTRUCTION_READ               0x03
+#define INSTRUCTION_WRITE      0x02
+#define INSTRUCTION_READ       0x03
 #define INSTRUCTION_BIT_MODIFY 0x05
 #define INSTRUCTION_LOAD_TXB(n)        (0x40 + 2 * (n))
 #define INSTRUCTION_READ_RXB(n)        (((n) == 0) ? 0x90 : 0x94)
 #define INSTRUCTION_BIT_MODIFY 0x05
 #define INSTRUCTION_LOAD_TXB(n)        (0x40 + 2 * (n))
 #define INSTRUCTION_READ_RXB(n)        (((n) == 0) ? 0x90 : 0x94)
-#define INSTRUCTION_RESET              0xC0
+#define INSTRUCTION_RESET      0xC0
 
 /* MPC251x registers */
 #define CANSTAT              0x0e
 
 /* MPC251x registers */
 #define CANSTAT              0x0e
 #define CNF2         0x29
 #  define CNF2_BTLMODE 0x80
 #define CNF3         0x28
 #define CNF2         0x29
 #  define CNF2_BTLMODE 0x80
 #define CNF3         0x28
-#  define CNF3_SOF     0x08
-#  define CNF3_WAKFIL  0x04
+#  define CNF3_SOF        0x08
+#  define CNF3_WAKFIL     0x04
 #  define CNF3_PHSEG2_MASK 0x07
 #define CANINTE              0x2b
 #  define CANINTE_MERRE 0x80
 #  define CNF3_PHSEG2_MASK 0x07
 #define CANINTE              0x2b
 #  define CANINTE_MERRE 0x80
 #  define TXBCTRL_TXERR 0x10
 #  define TXBCTRL_TXREQ 0x08
 #define RXBCTRL(n)  ((n * 0x10) + 0x60)
 #  define TXBCTRL_TXERR 0x10
 #  define TXBCTRL_TXREQ 0x08
 #define RXBCTRL(n)  ((n * 0x10) + 0x60)
-#  define RXBCTRL_BUKT  0x04
-#  define RXBCTRL_RXM0  0x20
-#  define RXBCTRL_RXM1  0x40
+#  define RXBCTRL_BUKT 0x04
+#  define RXBCTRL_RXM0 0x20
+#  define RXBCTRL_RXM1 0x40
 
 /* Buffer size required for the largest SPI transfer (i.e., reading a
  * frame). */
 
 /* Buffer size required for the largest SPI transfer (i.e., reading a
  * frame). */
@@ -176,6 +179,7 @@ struct mcp251x_priv {
        dma_addr_t spi_rx_dma;
 
        struct sk_buff *tx_skb;
        dma_addr_t spi_rx_dma;
 
        struct sk_buff *tx_skb;
+       int tx_len;
        struct workqueue_struct *wq;
        struct work_struct tx_work;
        struct work_struct irq_work;
        struct workqueue_struct *wq;
        struct work_struct tx_work;
        struct work_struct irq_work;
@@ -189,24 +193,41 @@ struct mcp251x_priv {
        int restart_tx;
 };
 
        int restart_tx;
 };
 
-static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+static void mcp251x_clean(struct mcp251x_priv *priv)
+{
+       if (priv->tx_skb)
+               dev_kfree_skb(priv->tx_skb);
+       if (priv->tx_len)
+               can_free_echo_skb(priv->net, 0);
+       priv->tx_skb = NULL;
+       priv->tx_len = 0;
+}
+
+/*
+  Note about handling of error return of mcp251x_spi_trans: accessing
+  registers via SPI is not really different conceptually than using
+  normal I/O assembler instructions, although it's much more
+  complicated from a practical POV. So it's not advisable to always
+  check the return value of this function. Imagine that every
+  read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
+  error();", it would be a great mess (well there are some situation
+  when exception handling C++ like could be useful after all). So we
+  just check that transfers are OK at the beginning of our
+  conversation with the chip and to avoid doing really nasty things
+  (like injecting bogus packets in the network stack).
+ */
+static int mcp251x_spi_trans(struct spi_device *spi, int len)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        struct spi_transfer t = {
                .tx_buf = priv->spi_tx_buf,
                .rx_buf = priv->spi_rx_buf,
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        struct spi_transfer t = {
                .tx_buf = priv->spi_tx_buf,
                .rx_buf = priv->spi_rx_buf,
-               .len = 3,
+               .len = len,
                .cs_change = 0,
        };
        struct spi_message m;
                .cs_change = 0,
        };
        struct spi_message m;
-       u8 val = 0;
        int ret;
 
        int ret;
 
-       mutex_lock(&priv->spi_lock);
-
-       priv->spi_tx_buf[0] = INSTRUCTION_READ;
-       priv->spi_tx_buf[1] = reg;
-
        spi_message_init(&m);
 
        if (mcp251x_enable_dma) {
        spi_message_init(&m);
 
        if (mcp251x_enable_dma) {
@@ -219,27 +240,31 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
 
        ret = spi_sync(spi, &m);
        if (ret < 0)
 
        ret = spi_sync(spi, &m);
        if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
-       else
-               val = priv->spi_rx_buf[2];
+               dev_err(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
+       return ret;
+}
+
+static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+{
+       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+       u8 val = 0;
+
+       mutex_lock(&priv->spi_lock);
+
+       priv->spi_tx_buf[0] = INSTRUCTION_READ;
+       priv->spi_tx_buf[1] = reg;
+
+       mcp251x_spi_trans(spi, 3);
+       val = priv->spi_rx_buf[2];
 
        mutex_unlock(&priv->spi_lock);
 
 
        mutex_unlock(&priv->spi_lock);
 
-       dev_dbg(&spi->dev, "%s: read %02x = %02x\n", __func__, reg, val);
        return val;
 }
 
 static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        return val;
 }
 
 static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-       struct spi_transfer t = {
-               .tx_buf = priv->spi_tx_buf,
-               .rx_buf = priv->spi_rx_buf,
-               .len = 3,
-               .cs_change = 0,
-       };
-       struct spi_message m;
-       int ret;
 
        mutex_lock(&priv->spi_lock);
 
 
        mutex_lock(&priv->spi_lock);
 
@@ -247,36 +272,15 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
        priv->spi_tx_buf[1] = reg;
        priv->spi_tx_buf[2] = val;
 
        priv->spi_tx_buf[1] = reg;
        priv->spi_tx_buf[2] = val;
 
-       spi_message_init(&m);
-
-       if (mcp251x_enable_dma) {
-               t.tx_dma = priv->spi_tx_dma;
-               t.rx_dma = priv->spi_rx_dma;
-               m.is_dma_mapped = 1;
-       }
-
-       spi_message_add_tail(&t, &m);
-
-       ret = spi_sync(spi, &m);
+       mcp251x_spi_trans(spi, 3);
 
        mutex_unlock(&priv->spi_lock);
 
        mutex_unlock(&priv->spi_lock);
-
-       if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed\n", __func__);
 }
 
 static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
                               u8 mask, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
 }
 
 static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
                               u8 mask, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-       struct spi_transfer t = {
-               .tx_buf = priv->spi_tx_buf,
-               .rx_buf = priv->spi_rx_buf,
-               .len = 4,
-               .cs_change = 0,
-       };
-       struct spi_message m;
-       int ret;
 
        mutex_lock(&priv->spi_lock);
 
 
        mutex_lock(&priv->spi_lock);
 
@@ -285,33 +289,18 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
        priv->spi_tx_buf[2] = mask;
        priv->spi_tx_buf[3] = val;
 
        priv->spi_tx_buf[2] = mask;
        priv->spi_tx_buf[3] = val;
 
-       spi_message_init(&m);
-
-       if (mcp251x_enable_dma) {
-               t.tx_dma = priv->spi_tx_dma;
-               t.rx_dma = priv->spi_rx_dma;
-               m.is_dma_mapped = 1;
-       }
-
-       spi_message_add_tail(&t, &m);
-
-       ret = spi_sync(spi, &m);
+       mcp251x_spi_trans(spi, 4);
 
        mutex_unlock(&priv->spi_lock);
 
        mutex_unlock(&priv->spi_lock);
-
-       if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed\n", __func__);
 }
 
 }
 
-static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
+static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
                          int tx_buf_idx)
 {
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        u32 sid, eid, exide, rtr;
 
                          int tx_buf_idx)
 {
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
        u32 sid, eid, exide, rtr;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
        exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
        if (exide)
                sid = (frame->can_id & CAN_EFF_MASK) >> 18;
        exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
        if (exide)
                sid = (frame->can_id & CAN_EFF_MASK) >> 18;
@@ -338,14 +327,6 @@ static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
                                          frame->data[i]);
                }
        } else {
                                          frame->data[i]);
                }
        } else {
-               struct spi_transfer t = {
-                       .tx_buf = priv->spi_tx_buf,
-                       .rx_buf = priv->spi_rx_buf,
-                       .cs_change = 0,
-                       .len = 6 + CAN_FRAME_MAX_DATA_LEN,
-               };
-               struct spi_message m;
-               int ret;
                u8 *tx_buf = priv->spi_tx_buf;
 
                mutex_lock(&priv->spi_lock);
                u8 *tx_buf = priv->spi_tx_buf;
 
                mutex_lock(&priv->spi_lock);
@@ -360,28 +341,11 @@ static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
 
                memcpy(tx_buf + 6, frame->data, frame->can_dlc);
 
 
                memcpy(tx_buf + 6, frame->data, frame->can_dlc);
 
-               spi_message_init(&m);
-
-               if (mcp251x_enable_dma) {
-                       t.tx_dma = priv->spi_tx_dma;
-                       t.rx_dma = priv->spi_rx_dma;
-                       m.is_dma_mapped = 1;
-               }
-
-               spi_message_add_tail(&t, &m);
-
-               ret = spi_sync(spi, &m);
+               mcp251x_spi_trans(spi, 6 + CAN_FRAME_MAX_DATA_LEN);
 
                mutex_unlock(&priv->spi_lock);
 
                mutex_unlock(&priv->spi_lock);
-
-               if (ret < 0) {
-                       dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__,
-                               ret);
-                       return -1;
-               }
        }
        mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
        }
        mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
-       return 0;
 }
 
 static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
 }
 
 static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
@@ -391,11 +355,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
        struct sk_buff *skb;
        struct can_frame *frame;
 
        struct sk_buff *skb;
        struct can_frame *frame;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
        skb = dev_alloc_skb(sizeof(struct can_frame));
        if (!skb) {
        skb = dev_alloc_skb(sizeof(struct can_frame));
        if (!skb) {
-               dev_dbg(&spi->dev, "%s: out of memory for Rx'd frame\n",
+               dev_err(&spi->dev, "%s: out of memory for Rx'd frame\n",
                        __func__);
                priv->net->stats.rx_dropped++;
                return;
                        __func__);
                priv->net->stats.rx_dropped++;
                return;
@@ -444,36 +406,16 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
                                                          6 + i);
                }
        } else {
                                                          6 + i);
                }
        } else {
-               struct spi_transfer t = {
-                       .tx_buf = priv->spi_tx_buf,
-                       .rx_buf = priv->spi_rx_buf,
-                       .cs_change = 0,
-                       .len = 14, /* RX buffer: RXBnCTRL to RXBnD7 */
-               };
-               struct spi_message m;
-               int ret;
                u8 *tx_buf = priv->spi_tx_buf;
                u8 *rx_buf = priv->spi_rx_buf;
                u8 *tx_buf = priv->spi_tx_buf;
                u8 *rx_buf = priv->spi_rx_buf;
+               int ret;
 
                mutex_lock(&priv->spi_lock);
 
                tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx);
 
 
                mutex_lock(&priv->spi_lock);
 
                tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx);
 
-               spi_message_init(&m);
-
-               if (mcp251x_enable_dma) {
-                       t.tx_dma = priv->spi_tx_dma;
-                       t.rx_dma = priv->spi_rx_dma;
-                       m.is_dma_mapped = 1;
-               }
-
-               spi_message_add_tail(&t, &m);
-
-               ret = spi_sync(spi, &m);
-
+               ret = mcp251x_spi_trans(spi, 14);
                if (ret < 0) {
                if (ret < 0) {
-                       dev_dbg(&spi->dev, "%s: failed: ret = %d\n",
-                               __func__, ret);
                        priv->net->stats.rx_errors++;
                        mutex_unlock(&priv->spi_lock);
                        return;
                        priv->net->stats.rx_errors++;
                        mutex_unlock(&priv->spi_lock);
                        return;
@@ -544,15 +486,14 @@ static int mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net)
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
 
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
-       if (priv->tx_skb) {
-               dev_warn(&spi->dev, "hard_xmit called with not null tx_skb\n");
+       if (priv->tx_skb || priv->tx_len) {
+               dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+               netif_stop_queue(net);
                return NETDEV_TX_BUSY;
        }
 
        if (skb->len != sizeof(struct can_frame)) {
                return NETDEV_TX_BUSY;
        }
 
        if (skb->len != sizeof(struct can_frame)) {
-               dev_dbg(&spi->dev, "dropping packet - bad length\n");
+               dev_err(&spi->dev, "dropping packet - bad length\n");
                dev_kfree_skb(skb);
                net->stats.tx_dropped++;
                return 0;
                dev_kfree_skb(skb);
                net->stats.tx_dropped++;
                return 0;
@@ -569,11 +510,13 @@ static int mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net)
 static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
 static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
-       struct spi_device *spi = priv->spi;
-
-       dev_dbg(&spi->dev, "%s (unimplemented)\n", __func__);
 
        switch (mode) {
 
        switch (mode) {
+       case CAN_MODE_START:
+               /* we have to delay work since SPI I/O may sleep */
+               priv->restart_tx = 1;
+               queue_work(priv->wq, &priv->irq_work);
+               break;
        default:
                return -EOPNOTSUPP;
        }
        default:
                return -EOPNOTSUPP;
        }
@@ -601,14 +544,15 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
                /* Wait for the device to enter normal mode */
                timeout = jiffies + HZ;
                while (mcp251x_read_reg(spi, CANSTAT) & 0xE0) {
                /* Wait for the device to enter normal mode */
                timeout = jiffies + HZ;
                while (mcp251x_read_reg(spi, CANSTAT) & 0xE0) {
-                       udelay(10);
+                       schedule();
                        if (time_after(jiffies, timeout)) {
                                dev_err(&spi->dev, "MCP251x didn't"
                                        " enter in normal mode\n");
                        if (time_after(jiffies, timeout)) {
                                dev_err(&spi->dev, "MCP251x didn't"
                                        " enter in normal mode\n");
-                               break;
+                               return;
                        }
                }
        }
                        }
                }
        }
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
 }
 
 static int mcp251x_do_set_bittiming(struct net_device *net)
 }
 
 static int mcp251x_do_set_bittiming(struct net_device *net)
@@ -642,18 +586,18 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
        return 0;
 }
 
        return 0;
 }
 
-static void mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
+static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
                          struct spi_device *spi)
 {
        int ret;
 
        /* Set initial baudrate. Make sure that registers are updated
           always by explicitly calling mcp251x_do_set_bittiming */
                          struct spi_device *spi)
 {
        int ret;
 
        /* Set initial baudrate. Make sure that registers are updated
           always by explicitly calling mcp251x_do_set_bittiming */
-       ret = can_set_bittiming(net);
-       if (ret)
+       ret = open_candev(net);
+       if (ret) {
                dev_err(&spi->dev, "unable to set initial baudrate!\n");
                dev_err(&spi->dev, "unable to set initial baudrate!\n");
-       else
-               mcp251x_do_set_bittiming(net);
+               return ret;
+       }
 
        /* Enable RX0->RX1 buffer roll over and disable filters */
        mcp251x_write_bits(spi, RXBCTRL(0),
 
        /* Enable RX0->RX1 buffer roll over and disable filters */
        mcp251x_write_bits(spi, RXBCTRL(0),
@@ -662,10 +606,7 @@ static void mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
        mcp251x_write_bits(spi, RXBCTRL(1),
                           RXBCTRL_RXM0 | RXBCTRL_RXM1,
                           RXBCTRL_RXM0 | RXBCTRL_RXM1);
        mcp251x_write_bits(spi, RXBCTRL(1),
                           RXBCTRL_RXM0 | RXBCTRL_RXM1,
                           RXBCTRL_RXM0 | RXBCTRL_RXM1);
-
-       dev_dbg(&spi->dev, "%s RXBCTL 0 and 1: %02x %02x\n", __func__,
-               mcp251x_read_reg(spi, RXBCTRL(0)),
-               mcp251x_read_reg(spi, RXBCTRL(1)));
+       return 0;
 }
 
 static void mcp251x_hw_reset(struct spi_device *spi)
 }
 
 static void mcp251x_hw_reset(struct spi_device *spi)
@@ -682,7 +623,7 @@ static void mcp251x_hw_reset(struct spi_device *spi)
        mutex_unlock(&priv->spi_lock);
 
        if (ret < 0)
        mutex_unlock(&priv->spi_lock);
 
        if (ret < 0)
-               dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
+               dev_err(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
        /* wait for reset to finish */
        mdelay(10);
 }
        /* wait for reset to finish */
        mdelay(10);
 }
@@ -708,18 +649,22 @@ static int mcp251x_open(struct net_device *net)
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
-
-       dev_dbg(&spi->dev, "%s\n", __func__);
+       int ret;
 
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(1);
 
        priv->force_quit = 0;
        priv->tx_skb = NULL;
 
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(1);
 
        priv->force_quit = 0;
        priv->tx_skb = NULL;
+       priv->tx_len = 0;
        enable_irq(spi->irq);
        mcp251x_hw_wakeup(spi);
        mcp251x_hw_reset(spi);
        enable_irq(spi->irq);
        mcp251x_hw_wakeup(spi);
        mcp251x_hw_reset(spi);
-       mcp251x_setup(net, priv, spi);
+       ret = mcp251x_setup(net, priv, spi);
+       if (ret < 0) {
+               disable_irq(spi->irq);
+               return ret;
+       }
        mcp251x_set_normal_mode(spi);
        netif_wake_queue(net);
 
        mcp251x_set_normal_mode(spi);
        netif_wake_queue(net);
 
@@ -732,8 +677,6 @@ static int mcp251x_stop(struct net_device *net)
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
 
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
        /* Disable and clear pending interrupts */
        mcp251x_write_reg(spi, CANINTE, 0x00);
        mcp251x_write_reg(spi, CANINTF, 0x00);
        /* Disable and clear pending interrupts */
        mcp251x_write_reg(spi, CANINTE, 0x00);
        mcp251x_write_reg(spi, CANINTF, 0x00);
@@ -743,10 +686,9 @@ static int mcp251x_stop(struct net_device *net)
        flush_workqueue(priv->wq);
 
        mcp251x_write_reg(spi, TXBCTRL(0), 0);
        flush_workqueue(priv->wq);
 
        mcp251x_write_reg(spi, TXBCTRL(0), 0);
-       if (priv->tx_skb) {
+       if (priv->tx_skb || priv->tx_len) {
                net->stats.tx_errors++;
                net->stats.tx_errors++;
-               dev_kfree_skb(priv->tx_skb);
-               priv->tx_skb = NULL;
+               mcp251x_clean(priv);
        }
 
        mcp251x_hw_sleep(spi);
        }
 
        mcp251x_hw_sleep(spi);
@@ -754,25 +696,8 @@ static int mcp251x_stop(struct net_device *net)
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(0);
 
        if (pdata->transceiver_enable)
                pdata->transceiver_enable(0);
 
-       return 0;
-}
-
-static int mcp251x_do_get_state(struct net_device *net, enum can_state *state)
-{
-       struct mcp251x_priv *priv = netdev_priv(net);
-       struct spi_device *spi = priv->spi;
-       u8 eflag;
-
-       eflag = mcp251x_read_reg(spi, EFLG);
-
-       if (eflag & EFLG_TXBO)
-               *state = CAN_STATE_BUS_OFF;
-       else if (eflag & (EFLG_RXEP | EFLG_TXEP))
-               *state = CAN_STATE_BUS_PASSIVE;
-       else if (eflag & EFLG_EWARN)
-               *state = CAN_STATE_BUS_WARNING;
-       else
-               *state = CAN_STATE_ACTIVE;
+       priv->can.state = CAN_STATE_STOPPED;
+       close_candev(net);
 
        return 0;
 }
 
        return 0;
 }
@@ -782,15 +707,19 @@ static void mcp251x_tx_work_handler(struct work_struct *ws)
        struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
                                                 tx_work);
        struct spi_device *spi = priv->spi;
        struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
                                                 tx_work);
        struct spi_device *spi = priv->spi;
+       struct net_device *net = priv->net;
        struct can_frame *frame;
 
        struct can_frame *frame;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
+       WARN_ON(!priv->tx_skb);
+       WARN_ON(priv->tx_len);
        if (priv->tx_skb) {
                frame = (struct can_frame *)priv->tx_skb->data;
                if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
                        frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
                mcp251x_hw_tx(spi, frame, 0);
        if (priv->tx_skb) {
                frame = (struct can_frame *)priv->tx_skb->data;
                if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
                        frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
                mcp251x_hw_tx(spi, frame, 0);
+               priv->tx_len = 1 + frame->can_dlc;
+               can_put_echo_skb(priv->tx_skb, net, 0);
+               priv->tx_skb = NULL;
        }
 }
 
        }
 }
 
@@ -802,19 +731,19 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
        struct net_device *net = priv->net;
        u8 intf;
        u8 txbnctrl;
        struct net_device *net = priv->net;
        u8 intf;
        u8 txbnctrl;
+       enum can_state new_state;
 
        if (priv->after_suspend) {
 
        if (priv->after_suspend) {
-               /* Wait whilst the device wakes up */
+               /* Wait whilst the device wakes up WARN_ON */
                mdelay(10);
                mcp251x_hw_reset(spi);
                mcp251x_setup(net, priv, spi);
                if (priv->after_suspend & AFTER_SUSPEND_UP) {
                        netif_device_attach(net);
                        /* clear since we lost tx buffer */
                mdelay(10);
                mcp251x_hw_reset(spi);
                mcp251x_setup(net, priv, spi);
                if (priv->after_suspend & AFTER_SUSPEND_UP) {
                        netif_device_attach(net);
                        /* clear since we lost tx buffer */
-                       if (priv->tx_skb) {
+                       if (priv->tx_skb || priv->tx_len) {
                                net->stats.tx_errors++;
                                net->stats.tx_errors++;
-                               dev_kfree_skb(priv->tx_skb);
-                               priv->tx_skb = NULL;
+                               mcp251x_clean(priv);
                                netif_wake_queue(net);
                        }
                        mcp251x_set_normal_mode(spi);
                                netif_wake_queue(net);
                        }
                        mcp251x_set_normal_mode(spi);
@@ -827,14 +756,14 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
        while (!priv->force_quit && !freezing(current)) {
                if (priv->restart_tx) {
                        priv->restart_tx = 0;
        while (!priv->force_quit && !freezing(current)) {
                if (priv->restart_tx) {
                        priv->restart_tx = 0;
-                       dev_warn(&spi->dev,
-                                "timeout in txing a packet, restarting\n");
+                       dev_dbg(&spi->dev,
+                               "timeout in txing a packet, restarting\n");
                        mcp251x_write_reg(spi, TXBCTRL(0), 0);
                        mcp251x_write_reg(spi, TXBCTRL(0), 0);
-                       if (priv->tx_skb) {
+                       if (priv->tx_skb || priv->tx_len) {
                                net->stats.tx_errors++;
                                net->stats.tx_errors++;
-                               dev_kfree_skb(priv->tx_skb);
-                               priv->tx_skb = NULL;
+                               mcp251x_clean(priv);
                        }
                        }
+                       priv->can.can_stats.restarts++;
                        netif_wake_queue(net);
                }
 
                        netif_wake_queue(net);
                }
 
@@ -849,27 +778,18 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                        break;
                mcp251x_write_bits(spi, CANINTF, intf, 0x00);
 
                        break;
                mcp251x_write_bits(spi, CANINTF, intf, 0x00);
 
-               dev_dbg(&spi->dev, "interrupt:%s%s%s%s%s%s%s%s\n",
-                       (intf & CANINTF_MERRF) ? " MERR" : "",
-                       (intf & CANINTF_WAKIF) ? " WAK" : "",
-                       (intf & CANINTF_ERRIF) ? " ERR" : "",
-                       (intf & CANINTF_TX2IF) ? " TX2" : "",
-                       (intf & CANINTF_TX1IF) ? " TX1" : "",
-                       (intf & CANINTF_TX0IF) ? " TX0" : "",
-                       (intf & CANINTF_RX1IF) ? " RX1" : "",
-                       (intf & CANINTF_RX0IF) ? " RX0" : "");
-
                if (intf & CANINTF_WAKIF)
                        complete(&priv->awake);
 
                if (intf & CANINTF_MERRF) {
                if (intf & CANINTF_WAKIF)
                        complete(&priv->awake);
 
                if (intf & CANINTF_MERRF) {
-                       /* if there are no pending Tx buffers, restart queue */
+                       /* if there are pending Tx buffers, restart queue */
                        txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
                        if (!(txbnctrl & TXBCTRL_TXREQ)) {
                        txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
                        if (!(txbnctrl & TXBCTRL_TXREQ)) {
-                               if (priv->tx_skb) {
+                               WARN_ON(priv->tx_skb);
+                               WARN_ON(!priv->tx_len);
+                               if (priv->tx_skb || priv->tx_len) {
                                        net->stats.tx_errors++;
                                        net->stats.tx_errors++;
-                                       dev_kfree_skb(priv->tx_skb);
-                                       priv->tx_skb = NULL;
+                                       mcp251x_clean(priv);
                                }
                                netif_wake_queue(net);
                        }
                                }
                                netif_wake_queue(net);
                        }
@@ -880,9 +800,7 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                        struct can_frame *frame = NULL;
                        u8 eflag = mcp251x_read_reg(spi, EFLG);
 
                        struct can_frame *frame = NULL;
                        u8 eflag = mcp251x_read_reg(spi, EFLG);
 
-                       dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflag);
-
-                       /* Create error frame */
+                       /* create error frame */
                        skb = dev_alloc_skb(sizeof(struct can_frame));
                        if (skb) {
                                frame = (struct can_frame *)
                        skb = dev_alloc_skb(sizeof(struct can_frame));
                        if (skb) {
                                frame = (struct can_frame *)
@@ -918,6 +836,7 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                                }
                        }
 
                                }
                        }
 
+                       /* update net stats */
                        if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
                                if (eflag & EFLG_RX0OVR)
                                        net->stats.rx_over_errors++;
                        if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
                                if (eflag & EFLG_RX0OVR)
                                        net->stats.rx_over_errors++;
@@ -929,21 +848,59 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                                          CAN_ERR_CRTL_RX_OVERFLOW;
                                }
                        }
                                          CAN_ERR_CRTL_RX_OVERFLOW;
                                }
                        }
+
+                       /* update can state */
+                       if (eflag & EFLG_TXBO) {
+                               new_state = CAN_STATE_BUS_OFF;
+                               can_bus_off(net);
+                       } else if (eflag & EFLG_TXEP)
+                               new_state = CAN_STATE_ERROR_PASSIVE;
+                       else if (eflag & EFLG_RXEP)
+                               new_state = CAN_STATE_ERROR_PASSIVE;
+                       else if (eflag & EFLG_TXWAR)
+                               new_state = CAN_STATE_ERROR_WARNING;
+                       else if (eflag & EFLG_RXWAR)
+                               new_state = CAN_STATE_ERROR_WARNING;
+                       else
+                               new_state = CAN_STATE_ERROR_ACTIVE;
+
                        mcp251x_write_reg(spi, EFLG, 0x00);
 
                        if (skb)
                                netif_rx(skb);
                        mcp251x_write_reg(spi, EFLG, 0x00);
 
                        if (skb)
                                netif_rx(skb);
+               } else
+                       new_state = CAN_STATE_ERROR_ACTIVE;
+
+               /* update can state statistics */
+               switch (priv->can.state) {
+               case CAN_STATE_ERROR_ACTIVE:
+                       if (new_state >= CAN_STATE_ERROR_WARNING &&
+                           new_state <= CAN_STATE_BUS_OFF)
+                               priv->can.can_stats.error_warning++;
+               case CAN_STATE_ERROR_WARNING:   /* fallthrough */
+                       if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+                           new_state <= CAN_STATE_BUS_OFF)
+                               priv->can.can_stats.error_passive++;
+                       break;
+               case CAN_STATE_BUS_OFF:
+                       if (new_state <= CAN_STATE_ERROR_PASSIVE)
+                               netif_carrier_on(net);
+                       break;
+               default:
+                       break;
                }
                }
+               priv->can.state = new_state;
 
                if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
 
                if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
-                       if (priv->tx_skb) {
-                               net->stats.tx_packets++;
-                               net->stats.tx_bytes +=
-                                       ((struct can_frame *)
-                                        (priv->tx_skb->data))->can_dlc;
-                               dev_kfree_skb(priv->tx_skb);
-                               priv->tx_skb = NULL;
+                       net->stats.tx_packets++;
+                       net->stats.tx_bytes += priv->tx_len - 1;
+                       WARN_ON(priv->tx_skb);
+                       WARN_ON(!priv->tx_len);
+                       if (priv->tx_len) {
+                               can_get_echo_skb(net, 0);
+                               priv->tx_len = 0;
                        }
                        }
+                       mcp251x_clean(priv);
                        netif_wake_queue(net);
                }
 
                        netif_wake_queue(net);
                }
 
@@ -956,8 +913,6 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
        }
 
        mcp251x_read_reg(spi, CANSTAT);
        }
 
        mcp251x_read_reg(spi, CANSTAT);
-
-       dev_dbg(&spi->dev, "interrupt ended\n");
 }
 
 static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
 }
 
 static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
@@ -965,7 +920,6 @@ static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
        struct net_device *net = (struct net_device *)dev_id;
        struct mcp251x_priv *priv = netdev_priv(net);
 
        struct net_device *net = (struct net_device *)dev_id;
        struct mcp251x_priv *priv = netdev_priv(net);
 
-       dev_dbg(&priv->spi->dev, "%s: irq\n", __func__);
        /* Schedule bottom half */
        if (!work_pending(&priv->irq_work))
                queue_work(priv->wq, &priv->irq_work);
        /* Schedule bottom half */
        if (!work_pending(&priv->irq_work))
                queue_work(priv->wq, &priv->irq_work);
@@ -973,15 +927,16 @@ static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
        return IRQ_HANDLED;
 }
 
-static void mcp251x_tx_timeout(struct net_device *net)
-{
-       struct mcp251x_priv *priv = netdev_priv(net);
-
-       priv->restart_tx = 1;
-       queue_work(priv->wq, &priv->irq_work);
-}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops mcp251x_netdev_ops = {
+       .ndo_open       = mcp251x_open,
+       .ndo_stop       = mcp251x_stop,
+       .ndo_start_xmit = mcp251x_hard_start_xmit,
+};
+#endif
 
 
-static struct net_device *alloc_mcp251x_netdev(int sizeof_priv)
+static struct net_device *alloc_mcp251x_netdev(int sizeof_priv,
+                               struct mcp251x_platform_data *pdata)
 {
        struct net_device *net;
        struct mcp251x_priv *priv;
 {
        struct net_device *net;
        struct mcp251x_priv *priv;
@@ -992,15 +947,19 @@ static struct net_device *alloc_mcp251x_netdev(int sizeof_priv)
 
        priv = netdev_priv(net);
 
 
        priv = netdev_priv(net);
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       net->netdev_ops         = &mcp251x_netdev_ops;
+#else
        net->open               = mcp251x_open;
        net->stop               = mcp251x_stop;
        net->hard_start_xmit    = mcp251x_hard_start_xmit;
        net->open               = mcp251x_open;
        net->stop               = mcp251x_stop;
        net->hard_start_xmit    = mcp251x_hard_start_xmit;
-       net->tx_timeout         = mcp251x_tx_timeout;
-       net->watchdog_timeo     = HZ;
+#endif
+       net->flags              |= IFF_ECHO;
 
        priv->can.bittiming_const = &mcp251x_bittiming_const;
 
        priv->can.bittiming_const = &mcp251x_bittiming_const;
-       priv->can.do_get_state    = mcp251x_do_get_state;
        priv->can.do_set_mode     = mcp251x_do_set_mode;
        priv->can.do_set_mode     = mcp251x_do_set_mode;
+       priv->can.clock.freq      = pdata->oscillator_frequency / 2;
+       priv->can.do_set_bittiming      = mcp251x_do_set_bittiming;
 
        priv->net = net;
 
 
        priv->net = net;
 
@@ -1020,7 +979,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        }
 
        /* Allocate can/net device */
        }
 
        /* Allocate can/net device */
-       net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv));
+       net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv), pdata);
        if (!net) {
                ret = -ENOMEM;
                goto error_alloc;
        if (!net) {
                ret = -ENOMEM;
                goto error_alloc;
@@ -1032,8 +991,6 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        priv->spi = spi;
        mutex_init(&priv->spi_lock);
 
        priv->spi = spi;
        mutex_init(&priv->spi_lock);
 
-       priv->can.bittiming.clock = pdata->oscillator_frequency / 2;
-
        /* If requested, allocate DMA buffers */
        if (mcp251x_enable_dma) {
                spi->dev.coherent_dma_mask = DMA_32BIT_MASK;
        /* If requested, allocate DMA buffers */
        if (mcp251x_enable_dma) {
                spi->dev.coherent_dma_mask = DMA_32BIT_MASK;
index 1f7dbfb1ef1b31f12bbe424b2e97c577b227b7cd..2f8fd1ef10f24e50b3aacda600bc74226da2958b 100644 (file)
@@ -19,6 +19,8 @@ obj-$(CONFIG_CAN_MPC52XX)     += mscan-mpc52xx.o
 
 mscan-mpc52xx-objs     := mscan.o mpc52xx_can.o
 
 
 mscan-mpc52xx-objs     := mscan.o mpc52xx_can.o
 
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+ifeq ($(CONFIG_CAN_DEBUG_DEVICES),y)
+       EXTRA_CFLAGS += -DDEBUG
+endif
 
 endif
 
 endif
index 9279c9af0975333d147f5ee482fc99b6d0179425..6a3d608bc4ba9bb7846cc5658e88be1af74adce0 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
@@ -39,7 +39,7 @@
 
 #include "mscan.h"
 
 
 #include "mscan.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
 
 RCSID("$Id$");
 
 
 RCSID("$Id$");
 
@@ -269,7 +269,11 @@ static unsigned int  __devinit mpc52xx_can_xtal_freq(struct device_node *np)
        unsigned int freq;
        u32 val;
 
        unsigned int freq;
        u32 val;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
        freq = mpc52xx_find_ipb_freq(np);
        freq = mpc52xx_find_ipb_freq(np);
+#else
+       freq = mpc5xxx_get_bus_frequency(np);
+#endif
        if (!freq)
                return 0;
 
        if (!freq)
                return 0;
 
@@ -317,8 +321,13 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct device_node *np,
 
        pvr = mfspr(SPRN_PVR);
 
 
        pvr = mfspr(SPRN_PVR);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
        if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
                return mpc52xx_find_ipb_freq(np);
        if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
                return mpc52xx_find_ipb_freq(np);
+#else
+       if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
+               return mpc5xxx_get_bus_frequency(np);
+#endif
 
        return mpc52xx_can_xtal_freq(np);
 }
 
        return mpc52xx_can_xtal_freq(np);
 }
@@ -384,8 +393,8 @@ static int __devinit mpc52xx_can_probe(struct of_device *ofdev,
                clock_src = MSCAN_CLKSRC_BUS;
        else
                clock_src = MSCAN_CLKSRC_XTAL;
                clock_src = MSCAN_CLKSRC_BUS;
        else
                clock_src = MSCAN_CLKSRC_XTAL;
-       priv->bittiming.clock = mpc52xx_can_clock_freq(np, clock_src);
-       if (!priv->bittiming.clock) {
+       priv->clock.freq = mpc52xx_can_clock_freq(np, clock_src);
+       if (!priv->clock.freq) {
                dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n");
                err = -ENODEV;
                goto exit_free_mscan;
                dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n");
                err = -ENODEV;
                goto exit_free_mscan;
@@ -403,7 +412,7 @@ static int __devinit mpc52xx_can_probe(struct of_device *ofdev,
        dev_set_drvdata(&ofdev->dev, dev);
 
        dev_info(&ofdev->dev, "MSCAN at 0x%lx, irq %d, clock %d Hz\n",
        dev_set_drvdata(&ofdev->dev, dev);
 
        dev_info(&ofdev->dev, "MSCAN at 0x%lx, irq %d, clock %d Hz\n",
-                dev->base_addr, dev->irq, priv->bittiming.clock);
+                dev->base_addr, dev->irq, priv->clock.freq);
 
        return 0;
 
 
        return 0;
 
index 13770630cd01306c0cd8f506a21e5e7ebe558891..51556f9f0e1b4c0e62bc66043c347af7dbfb62b0 100644 (file)
@@ -27,9 +27,9 @@
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/list.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/list.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
@@ -38,7 +38,7 @@
 
 #include "mscan.h"
 
 
 #include "mscan.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 #define MSCAN_NORMAL_MODE      0
 RCSID("$Id$");
 
 #define MSCAN_NORMAL_MODE      0
@@ -63,9 +63,10 @@ RCSID("$Id$");
 #define BTR1_SET_TSEG1(tseg1)  (((tseg1) - 1) &  BTR1_TSEG1_MASK)
 #define BTR1_SET_TSEG2(tseg2)  ((((tseg2) - 1) << BTR1_TSEG2_SHIFT) & \
                                 BTR1_TSEG2_MASK)
 #define BTR1_SET_TSEG1(tseg1)  (((tseg1) - 1) &  BTR1_TSEG1_MASK)
 #define BTR1_SET_TSEG2(tseg2)  ((((tseg2) - 1) << BTR1_TSEG2_SHIFT) & \
                                 BTR1_TSEG2_MASK)
-#define BTR1_SET_SAM(sam)      (((sam) & 1) << BTR1_SAM_SHIFT)
+#define BTR1_SET_SAM(sam)      ((sam) ? 1 << BTR1_SAM_SHIFT : 0)
 
 static struct can_bittiming_const mscan_bittiming_const = {
 
 static struct can_bittiming_const mscan_bittiming_const = {
+       .name = "mscan",
        .tseg1_min = 4,
        .tseg1_max = 16,
        .tseg2_min = 2,
        .tseg1_min = 4,
        .tseg1_max = 16,
        .tseg2_min = 2,
@@ -114,9 +115,9 @@ struct mscan_priv {
 #define F_TX_WAIT_ALL  2
 
 static enum can_state state_map[] = {
 #define F_TX_WAIT_ALL  2
 
 static enum can_state state_map[] = {
-       CAN_STATE_ACTIVE,
-       CAN_STATE_BUS_WARNING,
-       CAN_STATE_BUS_PASSIVE,
+       CAN_STATE_ERROR_ACTIVE,
+       CAN_STATE_ERROR_WARNING,
+       CAN_STATE_ERROR_PASSIVE,
        CAN_STATE_BUS_OFF
 };
 
        CAN_STATE_BUS_OFF
 };
 
@@ -131,10 +132,10 @@ static int mscan_set_mode(struct net_device *dev, u8 mode)
        if (mode != MSCAN_NORMAL_MODE) {
 
                if (priv->tx_active) {
        if (mode != MSCAN_NORMAL_MODE) {
 
                if (priv->tx_active) {
-                       /* Abort transfers before going to sleep */
-                       out_8(&regs->cantier, 0);
+                       /* Abort transfers before going to sleep */#
                        out_8(&regs->cantarq, priv->tx_active);
                        out_8(&regs->cantarq, priv->tx_active);
-                       out_8(&regs->cantier, priv->tx_active);
+                       /* Suppress TX done interrupts */
+                       out_8(&regs->cantier, 0);
                }
 
                canctl1 = in_8(&regs->canctl1);
                }
 
                canctl1 = in_8(&regs->canctl1);
@@ -183,7 +184,7 @@ static int mscan_set_mode(struct net_device *dev, u8 mode)
                        if (i >= MSCAN_SET_MODE_RETRIES)
                                ret = -ENODEV;
                        else
                        if (i >= MSCAN_SET_MODE_RETRIES)
                                ret = -ENODEV;
                        else
-                               priv->can.state = CAN_STATE_ACTIVE;
+                               priv->can.state = CAN_STATE_ERROR_ACTIVE;
                }
        }
        return ret;
                }
        }
        return ret;
@@ -314,8 +315,6 @@ static inline int check_set_state(struct net_device *dev, u8 canrflg)
                              MSCAN_STATE_TX(canrflg))];
        if (priv->can.state < state)
                ret = 1;
                              MSCAN_STATE_TX(canrflg))];
        if (priv->can.state < state)
                ret = 1;
-       if (state == CAN_STATE_BUS_OFF)
-               can_bus_off(dev);
        priv->can.state = state;
        return ret;
 }
        priv->can.state = state;
        return ret;
 }
@@ -405,18 +404,20 @@ static int mscan_rx_poll(struct net_device *dev, int *budget)
                                frame->can_id |= CAN_ERR_CRTL;
                                frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                                stats->rx_over_errors++;
                                frame->can_id |= CAN_ERR_CRTL;
                                frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                                stats->rx_over_errors++;
+                               stats->rx_errors++;
                        } else
                                frame->data[1] = 0;
 
                        if (check_set_state(dev, canrflg)) {
                        } else
                                frame->data[1] = 0;
 
                        if (check_set_state(dev, canrflg)) {
-                               frame->can_id |= CAN_ERR_CRTL;
                                switch (priv->can.state) {
                                switch (priv->can.state) {
-                               case CAN_STATE_BUS_WARNING:
+                               case CAN_STATE_ERROR_WARNING:
+                                       frame->can_id |= CAN_ERR_CRTL;
+                                       priv->can.can_stats.error_warning++;
                                        if ((priv->shadow_statflg &
                                             MSCAN_RSTAT_MSK) <
                                            (canrflg & MSCAN_RSTAT_MSK))
                                                frame->data[1] |=
                                        if ((priv->shadow_statflg &
                                             MSCAN_RSTAT_MSK) <
                                            (canrflg & MSCAN_RSTAT_MSK))
                                                frame->data[1] |=
-                                                   CAN_ERR_CRTL_RX_WARNING;
+                                                       CAN_ERR_CRTL_RX_WARNING;
 
                                        if ((priv->shadow_statflg &
                                             MSCAN_TSTAT_MSK) <
 
                                        if ((priv->shadow_statflg &
                                             MSCAN_TSTAT_MSK) <
@@ -424,13 +425,15 @@ static int mscan_rx_poll(struct net_device *dev, int *budget)
                                                frame->data[1] |=
                                                        CAN_ERR_CRTL_TX_WARNING;
                                        break;
                                                frame->data[1] |=
                                                        CAN_ERR_CRTL_TX_WARNING;
                                        break;
-                               case CAN_STATE_BUS_PASSIVE:
+                               case CAN_STATE_ERROR_PASSIVE:
+                                       frame->can_id |= CAN_ERR_CRTL;
+                                       priv->can.can_stats.error_passive++;
                                        frame->data[1] |=
                                        frame->data[1] |=
-                                           CAN_ERR_CRTL_RX_PASSIVE;
+                                               CAN_ERR_CRTL_RX_PASSIVE;
                                        break;
                                case CAN_STATE_BUS_OFF:
                                        frame->can_id |= CAN_ERR_BUSOFF;
                                        break;
                                case CAN_STATE_BUS_OFF:
                                        frame->can_id |= CAN_ERR_BUSOFF;
-                                       frame->can_id &= ~CAN_ERR_CRTL;
+                                       can_bus_off(dev);
                                        break;
                                default:
                                        break;
                                        break;
                                default:
                                        break;
@@ -604,16 +607,16 @@ static int mscan_open(struct net_device *dev)
        struct mscan_priv *priv = netdev_priv(dev);
        struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
 
        struct mscan_priv *priv = netdev_priv(dev);
        struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
 
-       /* determine and set bittime */
-       ret = can_set_bittiming(dev);
+       /* common open */
+       ret = open_candev(dev);
        if (ret)
                return ret;
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
        napi_enable(&priv->napi);
 #endif
        if (ret)
                return ret;
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
        napi_enable(&priv->napi);
 #endif
-       ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);
 
 
+       ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);
        if (ret < 0) {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
                napi_disable(&priv->napi);
        if (ret < 0) {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
                napi_disable(&priv->napi);
@@ -641,16 +644,16 @@ static int mscan_close(struct net_device *dev)
        struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
        struct mscan_priv *priv = netdev_priv(dev);
 
        struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr;
        struct mscan_priv *priv = netdev_priv(dev);
 
+       netif_stop_queue(dev);
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
        napi_disable(&priv->napi);
 #endif
 
        out_8(&regs->cantier, 0);
        out_8(&regs->canrier, 0);
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
        napi_disable(&priv->napi);
 #endif
 
        out_8(&regs->cantier, 0);
        out_8(&regs->canrier, 0);
-       free_irq(dev->irq, dev);
        mscan_set_mode(dev, MSCAN_INIT_MODE);
        mscan_set_mode(dev, MSCAN_INIT_MODE);
-       can_close_cleanup(dev);
-       netif_stop_queue(dev);
+       close_candev(dev);
+       free_irq(dev->irq, dev);
        priv->open_time = 0;
 
        return 0;
        priv->open_time = 0;
 
        return 0;
index 0a05a0bf7cb996c0b53fa16e7bf0da1d4fe05e4e..f3524667116a2725121e5d914ba50797fecbb7db 100644 (file)
@@ -239,7 +239,8 @@ struct mscan_platform_data {
 #endif
 
 struct net_device *alloc_mscandev(void);
 #endif
 
 struct net_device *alloc_mscandev(void);
-/* clock_src:
+/*
+ * clock_src:
  *     1 = The MSCAN clock source is the onchip Bus Clock.
  *     0 = The MSCAN clock source is the chip Oscillator Clock.
  */
  *     1 = The MSCAN clock source is the onchip Bus Clock.
  *     0 = The MSCAN clock source is the chip Oscillator Clock.
  */
index 8c44d9fea32020d21ca8e89d7e60028168af983f..507e28dbf2d69057bf1512341ec6872c65ac4a44 100644 (file)
@@ -15,7 +15,7 @@ else
 
 -include $(TOPDIR)/Makefile.common
 
 
 -include $(TOPDIR)/Makefile.common
 
-obj-$(CONFIG_CAN_CCAN)         += ccan.o
-obj-$(CONFIG_CAN_H7202)                += h7202_can.o
+obj-$(CONFIG_CAN_CCAN_OLD)             += ccan.o
+obj-$(CONFIG_CAN_H7202_OLD)            += h7202_can.o
 
 endif
 
 endif
index bf8f9db4c57b357947016e983c2c1dc4ca85e40e..1abd0c01a5464da2f198680b5461e793b7056ddb 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
-#include <linux/can.h>
+#include <socketcan/can.h>
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
@@ -44,8 +44,8 @@
 #include <asm/io.h>
 #endif
 
 #include <asm/io.h>
 #endif
 
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
 #include "ccan.h"
 
 static u32 ccan_read_reg32(struct net_device *dev, enum c_regs reg)
 #include "ccan.h"
 
 static u32 ccan_read_reg32(struct net_device *dev, enum c_regs reg)
index b7a5460195e136e9dbf69957010753647599e970..dfba87517011c833be0a0cb9dc9a6d3c3c4225f3 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef __CCAN_H__
 #define __CCAN_H__
 
 #ifndef __CCAN_H__
 #define __CCAN_H__
 
-#include <linux/can.h>
+#include <socketcan/can.h>
 #include <linux/platform_device.h>
 
 #undef CCAN_DEBUG
 #include <linux/platform_device.h>
 
 #undef CCAN_DEBUG
index 5d6fa5ab09a7db49c93d85252ae54d6986995f3c..1b821a17f5a20ab5c04a4cb490d7d2c0530a6d77 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
index 16d585ecdfc074f831a75b1a50bb5a55dee3a040..6372aa621d53b9602cd724e89fcf6aee5fc97fbb 100644 (file)
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 
-#include <linux/can.h>
-#include <linux/can/ioctl.h> /* for struct can_device_stats */
+#include <socketcan/can.h>
+#include <socketcan/can/ioctl.h> /* for struct can_device_stats */
 #include "hal.h"
 #include "i82527.h"
 
 #include "hal.h"
 #include "i82527.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
 RCSID("$Id$");
 
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
@@ -1055,23 +1055,20 @@ static int can_close(struct net_device *dev)
        return 0;
 }
 
        return 0;
 }
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops can_netdev_ops = {
+       .ndo_open               = can_open,
+       .ndo_stop               = can_close,
+       .ndo_start_xmit         = can_start_xmit,
+       .ndo_tx_timeout         = can_tx_timeout,
+};
+#endif
+
 void can_netdev_setup(struct net_device *dev)
 {
        /* Fill in the the fields of the device structure
           with CAN netdev generic values */
 
 void can_netdev_setup(struct net_device *dev)
 {
        /* Fill in the the fields of the device structure
           with CAN netdev generic values */
 
-       dev->change_mtu                 = NULL;
-       dev->set_mac_address            = NULL;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-       dev->hard_header                = NULL;
-       dev->rebuild_header             = NULL;
-       dev->hard_header_cache          = NULL;
-       dev->header_cache_update        = NULL;
-       dev->hard_header_parse          = NULL;
-#else
-       dev->header_ops                 = NULL;
-#endif
-
        dev->type                       = ARPHRD_CAN;
        dev->hard_header_len            = 0;
        dev->mtu                        = sizeof(struct can_frame);
        dev->type                       = ARPHRD_CAN;
        dev->hard_header_len            = 0;
        dev->mtu                        = sizeof(struct can_frame);
@@ -1081,14 +1078,19 @@ void can_netdev_setup(struct net_device *dev)
        dev->flags                      = IFF_NOARP;
        dev->features                   = NETIF_F_NO_CSUM;
 
        dev->flags                      = IFF_NOARP;
        dev->features                   = NETIF_F_NO_CSUM;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops = &can_netdev_ops;
+#else
        dev->open                       = can_open;
        dev->stop                       = can_close;
        dev->hard_start_xmit            = can_start_xmit;
        dev->open                       = can_open;
        dev->stop                       = can_close;
        dev->hard_start_xmit            = can_start_xmit;
+       dev->tx_timeout                 = can_tx_timeout;
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        dev->get_stats                  = can_get_stats;
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        dev->get_stats                  = can_get_stats;
 #endif
 
-       dev->tx_timeout                 = can_tx_timeout;
        dev->watchdog_timeo             = TX_TIMEOUT;
 }
 
        dev->watchdog_timeo             = TX_TIMEOUT;
 }
 
index 6028e96138359de40a4bf8e287a270a8f5231706..e1b02aa2cefdb0d1594a54c4982f3df3685d73e1 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 
-#include <linux/can.h>
-#include <linux/can/ioctl.h>
+#include <socketcan/can.h>
+#include <socketcan/can/ioctl.h>
 #include "i82527.h"
 #include "hal.h"
 
 #include "i82527.h"
 #include "hal.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 extern struct net_device *can_dev[];
 RCSID("$Id$");
 
 extern struct net_device *can_dev[];
@@ -154,8 +154,13 @@ static int can_proc_read_reset(char *page, char **start, off_t off,
                            && (priv->state != STATE_RESET_MODE)) {
                                len += snprintf(page + len, PAGE_SIZE - len,
                                                "%s ", dev->name);
                            && (priv->state != STATE_RESET_MODE)) {
                                len += snprintf(page + len, PAGE_SIZE - len,
                                                "%s ", dev->name);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+                               dev->netdev_ops->ndo_stop(dev);
+                               dev->netdev_ops->ndo_open(dev);
+#else
                                dev->stop(dev);
                                dev->open(dev);
                                dev->stop(dev);
                                dev->open(dev);
+#endif
                                /* count number of restarts */
                                priv->can_stats.restarts++;
 
                                /* count number of restarts */
                                priv->can_stats.restarts++;
 
index 6da9572878cbc0647e0d90abee23b850b8822083..910d6f9e1e8ea5804ab14db69db38aef9d89a6ab 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #include <asm/io.h>
 #include <asm/mpc52xx.h>
 
 #include "mscan.h"
 
 #include <asm/io.h>
 #include <asm/mpc52xx.h>
 
 #include "mscan.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
 
 RCSID("$Id$");
 
 
 RCSID("$Id$");
 
index 2d6e13d36ea60e0c6368395be3dafe634a24a4fc..4329aeb6b09d975f52cdec5e841c756ff99e69a4 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
-#include <linux/can.h>
+#include <socketcan/can.h>
 #include <linux/list.h>
 #include <asm/io.h>
 
 #include <linux/list.h>
 #include <asm/io.h>
 
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
 #include "mscan.h"
 
 #include "mscan.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 #define MSCAN_NORMAL_MODE      0
 RCSID("$Id$");
 
 #define MSCAN_NORMAL_MODE      0
index 86a81e8bb1a2416a55f6f66291ad19dfa0a0e700..562133fdcc4d0d4cc4f6fc6b2f048df526772db5 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 
-#include <linux/can.h>
-#include <linux/can/ioctl.h>
+#include <socketcan/can.h>
+#include <socketcan/can/ioctl.h>
 #include "sja1000.h"
 #include "hal.h"
 
 #include "sja1000.h"
 #include "hal.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 extern struct net_device *can_dev[];
 RCSID("$Id$");
 
 extern struct net_device *can_dev[];
@@ -175,8 +175,13 @@ static int can_proc_read_reset(char *page, char **start, off_t off,
                            && (priv->state != STATE_RESET_MODE)) {
                                len += snprintf(page + len, PAGE_SIZE - len,
                                                "%s ", dev->name);
                            && (priv->state != STATE_RESET_MODE)) {
                                len += snprintf(page + len, PAGE_SIZE - len,
                                                "%s ", dev->name);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+                               dev->netdev_ops->ndo_stop(dev);
+                               dev->netdev_ops->ndo_open(dev);
+#else
                                dev->stop(dev);
                                dev->open(dev);
                                dev->stop(dev);
                                dev->open(dev);
+#endif
                                /* count number of restarts */
                                priv->can_stats.restarts++;
 
                                /* count number of restarts */
                                priv->can_stats.restarts++;
 
index c8876f36784bf8c41532111d89fdbc81031ecd89..97c8f0001e1a98d127db1fac083a67b4a3b0daf6 100644 (file)
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 
-#include <linux/can.h>
-#include <linux/can/ioctl.h> /* for struct can_device_stats */
+#include <socketcan/can.h>
+#include <socketcan/can/ioctl.h> /* for struct can_device_stats */
 #include "sja1000.h"
 #include "hal.h"
 
 #include "sja1000.h"
 #include "hal.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
 RCSID("$Id$");
 
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
@@ -1007,23 +1007,20 @@ static void test_if(struct net_device *dev)
 }
 #endif
 
 }
 #endif
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops can_netdev_ops = {
+       .ndo_open               = can_open,
+       .ndo_stop               = can_close,
+       .ndo_start_xmit         = can_start_xmit,
+       .ndo_tx_timeout         = can_tx_timeout,
+};
+#endif
+
 void can_netdev_setup(struct net_device *dev)
 {
        /* Fill in the the fields of the device structure
           with CAN netdev generic values */
 
 void can_netdev_setup(struct net_device *dev)
 {
        /* Fill in the the fields of the device structure
           with CAN netdev generic values */
 
-       dev->change_mtu                 = NULL;
-       dev->set_mac_address            = NULL;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-       dev->hard_header                = NULL;
-       dev->rebuild_header             = NULL;
-       dev->hard_header_cache          = NULL;
-       dev->header_cache_update        = NULL;
-       dev->hard_header_parse          = NULL;
-#else
-       dev->header_ops                 = NULL;
-#endif
-
        dev->type                       = ARPHRD_CAN;
        dev->hard_header_len            = 0;
        dev->mtu                        = sizeof(struct can_frame);
        dev->type                       = ARPHRD_CAN;
        dev->hard_header_len            = 0;
        dev->mtu                        = sizeof(struct can_frame);
@@ -1041,14 +1038,19 @@ void can_netdev_setup(struct net_device *dev)
 
        dev->features                   = NETIF_F_NO_CSUM;
 
 
        dev->features                   = NETIF_F_NO_CSUM;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops = &can_netdev_ops;
+#else
        dev->open                       = can_open;
        dev->stop                       = can_close;
        dev->hard_start_xmit            = can_start_xmit;
        dev->open                       = can_open;
        dev->stop                       = can_close;
        dev->hard_start_xmit            = can_start_xmit;
+       dev->tx_timeout                 = can_tx_timeout;
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        dev->get_stats                  = can_get_stats;
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        dev->get_stats                  = can_get_stats;
 #endif
 
-       dev->tx_timeout                 = can_tx_timeout;
        dev->watchdog_timeo             = TX_TIMEOUT;
 }
 
        dev->watchdog_timeo             = TX_TIMEOUT;
 }
 
index d88d51ea8046c20d32fcc4fd63d94b06fac3d72d..5fd822a2c8fd2c22f268d6c0d0d58018b110c56a 100644 (file)
@@ -14,19 +14,22 @@ modules modules_install clean:
 else
 
 -include $(TOPDIR)/Makefile.common
 else
 
 -include $(TOPDIR)/Makefile.common
-#EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/can/hal
 
 obj-$(CONFIG_CAN_SJA1000) += sja1000.o
 
 obj-$(CONFIG_CAN_SJA1000) += sja1000.o
+obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
 obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
 obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
 obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
 obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
+obj-$(CONFIG_CAN_EMS_104M) += ems_104m.o
 obj-$(CONFIG_CAN_ESD_PCI) += esd_pci.o
 obj-$(CONFIG_CAN_IXXAT_PCI) += ixxat_pci.o
 obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
 obj-$(CONFIG_CAN_PIPCAN) += pipcan.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
 
 obj-$(CONFIG_CAN_ESD_PCI) += esd_pci.o
 obj-$(CONFIG_CAN_IXXAT_PCI) += ixxat_pci.o
 obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
 obj-$(CONFIG_CAN_PIPCAN) += pipcan.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
 
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+ifeq ($(CONFIG_CAN_DEBUG_DEVICES),y)
+       EXTRA_CFLAGS += -DDEBUG
+endif
 
 endif
 
 endif
diff --git a/kernel/2.6/drivers/net/can/sja1000/ems_104m.c b/kernel/2.6/drivers/net/can/sja1000/ems_104m.c
new file mode 100644 (file)
index 0000000..e9b52c8
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2009 Sebastian Haas <haas@ems-wuensche.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#include <linux/io.h>
+#else
+#include <asm/io.h>
+#endif
+
+#include "sja1000.h"
+
+#define DRV_NAME  "ems_104m"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#error This driver does not support Kernel versions < 2.6.16
+#endif
+
+MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-104M cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-104M CAN card");
+MODULE_LICENSE("GPL v2");
+
+#define EMS_104M_MAX_DEV  4
+
+static unsigned long __devinitdata mem[EMS_104M_MAX_DEV];
+static int __devinitdata irq[EMS_104M_MAX_DEV];
+
+module_param_array(mem, ulong, NULL, S_IRUGO);
+MODULE_PARM_DESC(mem, "I/O memory address");
+
+module_param_array(irq, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(irq, "IRQ number");
+
+#define EMS_104M_MAX_CHAN 4
+
+struct ems_104m_card {
+       int channels;
+
+       struct net_device *net_dev[EMS_104M_MAX_CHAN];
+
+       void __iomem *base;
+       int irq;
+};
+
+#define EMS_104M_CAN_CLOCK (16000000 / 2)
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means  normal output mode , push-pull and the correct polarity.
+ */
+#define EMS_104M_OCR         (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define EMS_104M_CDR             (CDR_CBP | CDR_CLKOUT_MASK)
+#define EMS_104M_MEM_SIZE        0x2000 /* Size of the remapped io-memory */
+#define EMS_104M_CAN_BASE_OFFSET 0x100  /* Offset where controllers starts */
+#define EMS_104M_CAN_CTRL_SIZE   0x80   /* Memory size for each controller */
+
+#define EMS_104M_CARD_REG_IRQ_CTRL    7
+#define EMS_104M_CARD_REG_IRQ_STATUS  8
+#define EMS_104M_CARD_REG_VERSION     9
+
+#define EMS_104M_CARD_REG_CONTROL     4
+#define EMS_104M_CARD_REG_STATUS      6
+
+#define EMS_CMD_RESET 0x00  /* Perform a reset of the card */
+#define EMS_CMD_MAP   0x03  /* Map CAN controllers into card' memory */
+#define EMS_CMD_UMAP  0x02  /* Unmap CAN controllers from card' memory */
+
+static u8 ems_104m_read_reg(const struct sja1000_priv *priv, int port)
+{
+       return readb(priv->reg_base + port);
+}
+
+static void ems_104m_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
+{
+       writeb(val, priv->reg_base + port);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static irqreturn_t ems_104m_interrupt(int irq, void *dev_id,
+                                       struct pt_regs *regs)
+#else
+static irqreturn_t ems_104m_interrupt(int irq, void *dev_id)
+#endif
+{
+       struct ems_104m_card *card = dev_id;
+       struct net_device *dev;
+       irqreturn_t retval = IRQ_NONE;
+       int i, again;
+
+       do {
+               again = 0;
+
+               /* Check interrupt for each channel */
+               for (i = 0; i < EMS_104M_MAX_CHAN; i++) {
+                       dev = card->net_dev[i];
+                       if (!dev)
+                               continue;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+                       if (sja1000_interrupt(irq, dev, regs) == IRQ_HANDLED)
+                                       again = 1;
+#else
+                       if (sja1000_interrupt(irq, dev) == IRQ_HANDLED)
+                                       again = 1;
+#endif
+               }
+
+               /* At least one channel handled the interrupt */
+               if (again)
+                       retval = IRQ_HANDLED;
+       } while (again);
+
+       return retval;
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to set 'em into the PeliCAN mode
+ */
+static inline int ems_104m_check_chan(struct sja1000_priv *priv)
+{
+       unsigned char res;
+
+       /* Make sure SJA1000 is in reset mode */
+       ems_104m_write_reg(priv, REG_MOD, 1);
+
+       ems_104m_write_reg(priv, REG_CDR, CDR_PELICAN);
+
+       /* read reset-values */
+       res = ems_104m_read_reg(priv, REG_CDR);
+
+       if (res == CDR_PELICAN)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Probe ISA device for EMS CAN signature and register each available
+ * CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit ems_104m_probe(struct device *pdev, unsigned int idx)
+{
+       struct sja1000_priv *priv;
+       struct net_device *dev;
+       struct ems_104m_card *card;
+
+       int err, i;
+
+       /* Allocating card structures to hold addresses, ... */
+       card = kzalloc(sizeof(struct ems_104m_card), GFP_KERNEL);
+       if (card == NULL) {
+               dev_err(pdev, "couldn't allocate memory\n");
+               return -ENOMEM;
+       }
+
+       dev_set_drvdata(pdev, card);
+
+       card->channels = 0;
+       card->irq = irq[idx];
+
+       card->base = ioremap_nocache(mem[idx], EMS_104M_MEM_SIZE);
+       if (card->base == NULL) {
+               dev_err(pdev, "couldn't map memory\n");
+               err = -ENOMEM;
+               goto failure_cleanup;
+       }
+
+       /* Check for unique EMS CAN signature */
+       if (readw(card->base) != 0xAA55) {
+               dev_err(pdev, "No EMS CPC Card hardware found.\n");
+
+               err = -ENODEV;
+               goto failure_cleanup;
+       }
+
+       writeb(EMS_CMD_RESET, card->base);
+
+       /* Wait for reset to finish */
+       i = 0;
+       while (readb(card->base + EMS_104M_CARD_REG_STATUS) == 0x01) {
+               /* Check for timeout (50ms.) */
+               if (i >= 50) {
+                       dev_err(pdev, "couldn't reset card.\n");
+
+                       err = -EBUSY;
+                       goto failure_cleanup;
+               }
+
+               msleep(1);
+       }
+
+       /* Make sure CAN controllers are mapped into card's memory space */
+       writeb(EMS_CMD_MAP, card->base);
+       writeb(EMS_CMD_MAP, card->base); /* Second call to workaround bug */
+
+       /* Detect available channels */
+       for (i = 0; i < EMS_104M_MAX_CHAN; i++) {
+               dev = alloc_sja1000dev(0);
+               if (dev == NULL) {
+                       err = -ENOMEM;
+                       goto failure_cleanup;
+               }
+
+               card->net_dev[i] = dev;
+               priv = netdev_priv(dev);
+               priv->priv = card;
+               SET_NETDEV_DEV(dev, pdev);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+               priv->irq_flags = SA_SHIRQ;
+#else
+               priv->irq_flags = IRQF_SHARED;
+#endif
+               dev->irq = irq[idx];
+               priv->reg_base = card->base + EMS_104M_CAN_BASE_OFFSET
+                                       + (i * EMS_104M_CAN_CTRL_SIZE);
+
+               /* Check if channel is present */
+               if (ems_104m_check_chan(priv)) {
+                       priv->read_reg  = ems_104m_read_reg;
+                       priv->write_reg = ems_104m_write_reg;
+                       priv->can.clock.freq = EMS_104M_CAN_CLOCK;
+                       priv->ocr = EMS_104M_OCR;
+                       priv->cdr = EMS_104M_CDR;
+                       priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
+
+                       /* Register SJA1000 device */
+                       err = register_sja1000dev(dev);
+                       if (err) {
+                               dev_err(pdev, "registering device failed"
+                                   " (err=%d)\n", err);
+                               free_sja1000dev(dev);
+                               goto failure_cleanup;
+                       }
+
+                       /* Enable interrupts of this channel */
+                       writeb(0x3 << (i * 2),
+                           card->base + EMS_104M_CARD_REG_IRQ_CTRL);
+
+                       card->channels++;
+
+                       dev_info(pdev, "registered %s on channel at 0x%p,"
+                           " irq %d\n", dev->name, priv->reg_base, dev->irq);
+               } else {
+                       free_sja1000dev(dev);
+               }
+       }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       err = request_irq(card->irq, &ems_104m_interrupt, SA_SHIRQ,
+               DRV_NAME, (void *)card);
+#else
+       err = request_irq(card->irq, &ems_104m_interrupt, IRQF_SHARED,
+               DRV_NAME, (void *)card);
+#endif
+
+       if (err) {
+               dev_err(pdev, "registering device failed (err=%d)\n", err);
+               goto failure_cleanup;
+       }
+
+       return 0;
+
+failure_cleanup:
+       dev_err(pdev, "error: %d. Cleaning Up.\n", err);
+
+       if (card->base)
+               iounmap(card->base);
+
+       kfree(card);
+
+       return err;
+}
+
+/*
+ * Release claimed resources
+ */
+static int __devexit ems_104m_remove(struct device *pdev, unsigned int idx)
+{
+       struct ems_104m_card *card = dev_get_drvdata(pdev);
+       struct net_device *dev;
+       int i = 0;
+
+       if (!card)
+               return 0;
+
+       free_irq(card->irq, card);
+
+       for (i = 0; i < card->channels; i++) {
+               dev = card->net_dev[i];
+
+               if (!dev)
+                       continue;
+
+               dev_info(pdev, "removing %s on channel #%d\n", dev->name, i);
+               unregister_sja1000dev(dev);
+               free_sja1000dev(dev);
+       }
+
+       writeb(EMS_CMD_UMAP, card->base);
+
+       if (card->base != NULL)
+               iounmap(card->base);
+
+       kfree(card);
+
+       dev_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static int __devinit ems_104m_match(struct device *pdev, unsigned int idx)
+{
+       if (!mem[idx])
+               return 0;
+
+       if (!irq[idx]) {
+               dev_err(pdev, "insufficient parameters supplied\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct isa_driver ems_104m_driver = {
+       .match = ems_104m_match,
+       .probe = ems_104m_probe,
+       .remove = __devexit_p(ems_104m_remove),
+
+       .driver = {
+               .name = DRV_NAME,
+       },
+};
+
+static int __init ems_104m_init(void)
+{
+       int err = isa_register_driver(&ems_104m_driver, EMS_104M_MAX_DEV);
+
+       if (!err)
+               printk(KERN_INFO
+                      "Legacy %s driver for max. %d devices registered\n",
+                      DRV_NAME, EMS_104M_MAX_DEV);
+
+       return err;
+}
+
+static void __exit ems_104m_exit(void)
+{
+       isa_unregister_driver(&ems_104m_driver);
+}
+
+module_init(ems_104m_init);
+module_exit(ems_104m_exit);
+
index 05e5f6957947d9b9c030a82d2b1b851e4aae9613..9d867d49ca1bd9e8ff790bece0038fa5db8f2232 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 
 #define DRV_NAME  "ems_pci"
 
 
 #define DRV_NAME  "ems_pci"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+#error This driver does not support Kernel versions < 2.6.23
+#endif
+
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
 MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
 MODULE_LICENSE("GPL v2");
 
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
 MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
 MODULE_LICENSE("GPL v2");
 
-#define EMS_PCI_MAX_CHAN 2
+#define EMS_PCI_V1_MAX_CHAN 2
+#define EMS_PCI_V2_MAX_CHAN 4
+#define EMS_PCI_MAX_CHAN    EMS_PCI_V2_MAX_CHAN
 
 struct ems_pci_card {
 
 struct ems_pci_card {
+       int version;
        int channels;
 
        struct pci_dev *pci_dev;
        int channels;
 
        struct pci_dev *pci_dev;
@@ -66,13 +74,23 @@ struct ems_pci_card {
 #define PITA2_MISC          0x1c       /* Miscellaneous Register */
 #define PITA2_MISC_CONFIG   0x04000000 /* Multiplexed parallel interface */
 
 #define PITA2_MISC          0x1c       /* Miscellaneous Register */
 #define PITA2_MISC_CONFIG   0x04000000 /* Multiplexed parallel interface */
 
+/*
+ * Register definitions for the PLX 9030
+ */
+#define PLX_ICSR            0x4c   /* Interrupt Control/Status register */
+#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
+#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
+#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
+#define PLX_ICSR_ENA_CLR    (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
+                            PLX_ICSR_LINTI1_CLR)
+
 /*
  * The board configuration is probably following:
  * RX1 is connected to ground.
  * TX1 is not connected.
  * CLKO is not connected.
  * Setting the OCR register to 0xDA is a good idea.
 /*
  * The board configuration is probably following:
  * RX1 is connected to ground.
  * TX1 is not connected.
  * CLKO is not connected.
  * Setting the OCR register to 0xDA is a good idea.
- * This means  normal output mode , push-pull and the correct polarity.
+ * This means normal output mode, push-pull and the correct polarity.
  */
 #define EMS_PCI_OCR         (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
 
  */
 #define EMS_PCI_OCR         (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
 
@@ -83,17 +101,21 @@ struct ems_pci_card {
  * is driven by the first one CLKOUT output.
  */
 #define EMS_PCI_CDR             (CDR_CBP | CDR_CLKOUT_MASK)
  * is driven by the first one CLKOUT output.
  */
 #define EMS_PCI_CDR             (CDR_CBP | CDR_CLKOUT_MASK)
-#define EMS_PCI_MEM_SIZE        4096  /* Size of the remapped io-memory */
+
+#define EMS_PCI_V1_BASE_BAR     1
+#define EMS_PCI_V1_MEM_SIZE     4096
+#define EMS_PCI_V2_BASE_BAR     2
+#define EMS_PCI_V2_MEM_SIZE     128
 #define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
 #define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */
 
 #define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
 #define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */
 
-#define EMS_PCI_PORT_BYTES  0x4     /* Each register occupies 4 bytes */
-
-#define EMS_PCI_VENDOR_ID   0x110a  /* PCI device and vendor ID */
-#define EMS_PCI_DEVICE_ID   0x2104
-
 static struct pci_device_id ems_pci_tbl[] = {
 static struct pci_device_id ems_pci_tbl[] = {
-       {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       /* CPC-PCI v1 */
+       {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
+       /* CPC-PCI v2 */
+       {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
+       /* CPC-104P v2 */
+       {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
@@ -101,49 +123,64 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
 /*
  * Helper to read internal registers from card logic (not CAN)
  */
 /*
  * Helper to read internal registers from card logic (not CAN)
  */
-static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
 {
 {
-       return readb((void __iomem *)card->base_addr
-                       + (port * EMS_PCI_PORT_BYTES));
+       return readb(card->base_addr + (port * 4));
 }
 
 }
 
-static u8 ems_pci_read_reg(struct net_device *dev, int port)
+static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
 {
 {
-       return readb((void __iomem *)dev->base_addr
-                       + (port * EMS_PCI_PORT_BYTES));
+       return readb(priv->reg_base + (port * 4));
 }
 
 }
 
-static void ems_pci_write_reg(struct net_device *dev, int port, u8 val)
+static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
 {
 {
-       writeb(val, (void __iomem *)dev->base_addr
-               + (port * EMS_PCI_PORT_BYTES));
+       writeb(val, priv->reg_base + (port * 4));
 }
 
 }
 
-static void ems_pci_post_irq(struct net_device *dev)
+static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
 {
 {
-       struct sja1000_priv *priv = netdev_priv(dev);
        struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
 
        /* reset int flag of pita */
        struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
 
        /* reset int flag of pita */
-       writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
-               + PITA2_ICR);
+       writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+              card->conf_addr + PITA2_ICR);
+}
+
+static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
+{
+       return readb(priv->reg_base + port);
+}
+
+static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
+{
+       writeb(val, priv->reg_base + port);
+}
+
+static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
+{
+       struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+       writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
 }
 
 /*
  * Check if a CAN controller is present at the specified location
  * by trying to set 'em into the PeliCAN mode
  */
 }
 
 /*
  * Check if a CAN controller is present at the specified location
  * by trying to set 'em into the PeliCAN mode
  */
-static inline int ems_pci_check_chan(struct net_device *dev)
+static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
 {
        unsigned char res;
 
        /* Make sure SJA1000 is in reset mode */
 {
        unsigned char res;
 
        /* Make sure SJA1000 is in reset mode */
-       ems_pci_write_reg(dev, REG_MOD, 1);
+       priv->write_reg(priv, REG_MOD, 1);
 
 
-       ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN);
+       priv->write_reg(priv, REG_CDR, CDR_PELICAN);
 
        /* read reset-values */
 
        /* read reset-values */
-       res = ems_pci_read_reg(dev, REG_CDR);
+       res = priv->read_reg(priv, REG_CDR);
 
        if (res == CDR_PELICAN)
                return 1;
 
        if (res == CDR_PELICAN)
                return 1;
@@ -196,6 +233,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
        struct sja1000_priv *priv;
        struct net_device *dev;
        struct ems_pci_card *card;
        struct sja1000_priv *priv;
        struct net_device *dev;
        struct ems_pci_card *card;
+       int max_chan, mem_size, base_bar;
        int err, i;
 
        /* Enabling PCI device */
        int err, i;
 
        /* Enabling PCI device */
@@ -218,40 +256,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
 
        card->channels = 0;
 
 
        card->channels = 0;
 
-       /* Remap PITA configuration space, and controller memory area */
-       card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+       if (pdev->vendor == PCI_VENDOR_ID_PLX) {
+               card->version = 2; /* CPC-PCI v2 */
+               max_chan = EMS_PCI_V2_MAX_CHAN;
+               base_bar = EMS_PCI_V2_BASE_BAR;
+               mem_size = EMS_PCI_V2_MEM_SIZE;
+       } else {
+               card->version = 1; /* CPC-PCI v1 */
+               max_chan = EMS_PCI_V1_MAX_CHAN;
+               base_bar = EMS_PCI_V1_BASE_BAR;
+               mem_size = EMS_PCI_V1_MEM_SIZE;
+       }
+
+       /* Remap configuration space and controller memory area */
+       card->conf_addr = pci_iomap(pdev, 0, mem_size);
        if (card->conf_addr == NULL) {
                err = -ENOMEM;
        if (card->conf_addr == NULL) {
                err = -ENOMEM;
-
                goto failure_cleanup;
        }
 
                goto failure_cleanup;
        }
 
-       card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+       card->base_addr = pci_iomap(pdev, base_bar, mem_size);
        if (card->base_addr == NULL) {
                err = -ENOMEM;
        if (card->base_addr == NULL) {
                err = -ENOMEM;
-
                goto failure_cleanup;
        }
 
                goto failure_cleanup;
        }
 
-       /* Configure PITA-2 parallel interface (enable MUX) */
-       writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
-
-       /* Check for unique EMS CAN signature */
-       if (ems_pci_readb(card, 0) != 0x55 ||
-           ems_pci_readb(card, 1) != 0xAA ||
-           ems_pci_readb(card, 2) != 0x01 ||
-           ems_pci_readb(card, 3) != 0xCB ||
-           ems_pci_readb(card, 4) != 0x11) {
-               dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
-
-               err = -ENODEV;
-               goto failure_cleanup;
-       }
+       if (card->version == 1) {
+               /* Configure PITA-2 parallel interface (enable MUX) */
+               writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+               /* Check for unique EMS CAN signature */
+               if (ems_pci_v1_readb(card, 0) != 0x55 ||
+                   ems_pci_v1_readb(card, 1) != 0xAA ||
+                   ems_pci_v1_readb(card, 2) != 0x01 ||
+                   ems_pci_v1_readb(card, 3) != 0xCB ||
+                   ems_pci_v1_readb(card, 4) != 0x11) {
+                       dev_err(&pdev->dev,
+                               "Not EMS Dr. Thomas Wuensche interface\n");
+                       err = -ENODEV;
+                       goto failure_cleanup;
+               }
+       }
 
        ems_pci_card_reset(card);
 
        /* Detect available channels */
 
        ems_pci_card_reset(card);
 
        /* Detect available channels */
-       for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+       for (i = 0; i < max_chan; i++) {
                dev = alloc_sja1000dev(0);
                if (dev == NULL) {
                        err = -ENOMEM;
                dev = alloc_sja1000dev(0);
                if (dev == NULL) {
                        err = -ENOMEM;
@@ -261,25 +311,41 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
                card->net_dev[i] = dev;
                priv = netdev_priv(dev);
                priv->priv = card;
                card->net_dev[i] = dev;
                priv = netdev_priv(dev);
                priv->priv = card;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+               priv->irq_flags = SA_SHIRQ;
+#else
+               priv->irq_flags = IRQF_SHARED;
+#endif
 
                dev->irq = pdev->irq;
 
                dev->irq = pdev->irq;
-               dev->base_addr = (unsigned long)(card->base_addr
-                                               + EMS_PCI_CAN_BASE_OFFSET
-                                               + (i * EMS_PCI_CAN_CTRL_SIZE));
+               priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
+                                       + (i * EMS_PCI_CAN_CTRL_SIZE);
+               if (card->version == 1) {
+                       priv->read_reg  = ems_pci_v1_read_reg;
+                       priv->write_reg = ems_pci_v1_write_reg;
+                       priv->post_irq  = ems_pci_v1_post_irq;
+               } else {
+                       priv->read_reg  = ems_pci_v2_read_reg;
+                       priv->write_reg = ems_pci_v2_write_reg;
+                       priv->post_irq  = ems_pci_v2_post_irq;
+               }
 
                /* Check if channel is present */
 
                /* Check if channel is present */
-               if (ems_pci_check_chan(dev)) {
-                       priv->read_reg  = ems_pci_read_reg;
-                       priv->write_reg = ems_pci_write_reg;
-                       priv->post_irq  = ems_pci_post_irq;
-                       priv->can.bittiming.clock = EMS_PCI_CAN_CLOCK;
+               if (ems_pci_check_chan(priv)) {
+                       priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
                        priv->ocr = EMS_PCI_OCR;
                        priv->cdr = EMS_PCI_CDR;
 
                        SET_NETDEV_DEV(dev, &pdev->dev);
 
                        priv->ocr = EMS_PCI_OCR;
                        priv->cdr = EMS_PCI_CDR;
 
                        SET_NETDEV_DEV(dev, &pdev->dev);
 
-                       /* Enable interrupts from card */
-                       writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+                       if (card->version == 1)
+                               /* reset int flag of pita */
+                               writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+                                      card->conf_addr + PITA2_ICR);
+                       else
+                               /* enable IRQ in PLX 9030 */
+                               writel(PLX_ICSR_ENA_CLR,
+                                      card->conf_addr + PLX_ICSR);
 
                        /* Register SJA1000 device */
                        err = register_sja1000dev(dev);
 
                        /* Register SJA1000 device */
                        err = register_sja1000dev(dev);
@@ -292,9 +358,8 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
 
                        card->channels++;
 
 
                        card->channels++;
 
-                       dev_info(&pdev->dev, "Channel #%d at %#lX, irq %d\n",
-                                               i + 1, dev->base_addr,
-                                               dev->irq);
+                       dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n",
+                                       i + 1, priv->reg_base, dev->irq);
                } else {
                        free_sja1000dev(dev);
                }
                } else {
                        free_sja1000dev(dev);
                }
index 0f6219df9efd8ebc61d2b55373d3ef473e0f4ac4..75fcab46fe3f0359c9f9573253fdfe51eaf06058 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #include <asm/io.h>
 
 #include <pcmcia/cs_types.h>
 #include <asm/io.h>
 
 #include <pcmcia/cs_types.h>
 
 #define DRV_NAME  "ems_pcmcia"
 
 
 #define DRV_NAME  "ems_pcmcia"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#error This driver does not support Kernel versions < 2.6.16
+#endif
+
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-CARD cards");
 MODULE_SUPPORTED_DEVICE("EMS CPC-CARD CAN card");
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-CARD cards");
 MODULE_SUPPORTED_DEVICE("EMS CPC-CARD CAN card");
@@ -94,14 +99,15 @@ MODULE_DEVICE_TABLE (pcmcia, ems_pcmcia_tbl);
 
 static void ems_pcmcia_config(struct pcmcia_device *dev);
 
 
 static void ems_pcmcia_config(struct pcmcia_device *dev);
 
-static u8 ems_pcmcia_read_reg(struct net_device *dev, int port)
+static u8 ems_pcmcia_read_reg(const struct sja1000_priv *priv, int port)
 {
 {
-       return readb((void __iomem *)dev->base_addr + port);
+       return readb(priv->reg_base + port);
 }
 
 }
 
-static void ems_pcmcia_write_reg(struct net_device *dev, int port, u8 val)
+static void ems_pcmcia_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
 {
 {
-       writeb(val, (void __iomem *)dev->base_addr + port);
+       writeb(val, priv->reg_base + port);
 }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
 }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
@@ -116,6 +122,10 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
        irqreturn_t retval = IRQ_NONE;
        int i, again;
 
        irqreturn_t retval = IRQ_NONE;
        int i, again;
 
+       /* Card not present */
+       if (readw(card->base_addr) != 0xAA55)
+               return IRQ_HANDLED;
+
        do {
                again = 0;
 
        do {
                again = 0;
 
@@ -146,17 +156,17 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
  * Check if a CAN controller is present at the specified location
  * by trying to set 'em into the PeliCAN mode
  */
  * Check if a CAN controller is present at the specified location
  * by trying to set 'em into the PeliCAN mode
  */
-static inline int ems_pcmcia_check_chan(struct net_device *dev)
+static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)
 {
        unsigned char res;
 
        /* Make sure SJA1000 is in reset mode */
 {
        unsigned char res;
 
        /* Make sure SJA1000 is in reset mode */
-       ems_pcmcia_write_reg(dev, REG_MOD, 1);
+       ems_pcmcia_write_reg(priv, REG_MOD, 1);
 
 
-       ems_pcmcia_write_reg(dev, REG_CDR, CDR_PELICAN);
+       ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN);
 
        /* read reset-values */
 
        /* read reset-values */
-       res = ems_pcmcia_read_reg(dev, REG_CDR);
+       res = ems_pcmcia_read_reg(priv, REG_CDR);
 
        if (res == CDR_PELICAN)
                return 1;
 
        if (res == CDR_PELICAN)
                return 1;
@@ -259,16 +269,21 @@ static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
                priv->priv = card;
                SET_NETDEV_DEV(dev, &pdev->dev);
 
                priv->priv = card;
                SET_NETDEV_DEV(dev, &pdev->dev);
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+               priv->irq_flags = SA_SHIRQ;
+#else
+               priv->irq_flags = IRQF_SHARED;
+#endif
                dev->irq = pdev->irq.AssignedIRQ;
                dev->irq = pdev->irq.AssignedIRQ;
-               dev->base_addr = (unsigned long)(card->base_addr
+               priv->reg_base = (card->base_addr
                                        + EMS_PCMCIA_CAN_BASE_OFFSET
                                        + (i * EMS_PCMCIA_CAN_CTRL_SIZE));
 
                /* Check if channel is present */
                                        + EMS_PCMCIA_CAN_BASE_OFFSET
                                        + (i * EMS_PCMCIA_CAN_CTRL_SIZE));
 
                /* Check if channel is present */
-               if (ems_pcmcia_check_chan(dev)) {
+               if (ems_pcmcia_check_chan(priv)) {
                        priv->read_reg  = ems_pcmcia_read_reg;
                        priv->write_reg = ems_pcmcia_write_reg;
                        priv->read_reg  = ems_pcmcia_read_reg;
                        priv->write_reg = ems_pcmcia_write_reg;
-                       priv->can.bittiming.clock = EMS_PCMCIA_CAN_CLOCK;
+                       priv->can.clock.freq = EMS_PCMCIA_CAN_CLOCK;
                        priv->ocr = EMS_PCMCIA_OCR;
                        priv->cdr = EMS_PCMCIA_CDR;
                        priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
                        priv->ocr = EMS_PCMCIA_OCR;
                        priv->cdr = EMS_PCMCIA_CDR;
                        priv->flags |= SJA1000_CUSTOM_IRQ_HANDLER;
@@ -285,8 +300,8 @@ static int __devinit ems_pcmcia_add_card(struct pcmcia_device *pdev,
                        card->channels++;
 
                        printk(KERN_INFO "%s: registered %s on channel "
                        card->channels++;
 
                        printk(KERN_INFO "%s: registered %s on channel "
-                              "#%d at %lX, irq %d\n", DRV_NAME, dev->name,
-                              i, dev->base_addr, dev->irq);
+                              "#%d at 0x%p, irq %d\n", DRV_NAME, dev->name,
+                              i, priv->reg_base, dev->irq);
                } else {
                        free_sja1000dev(dev);
                }
                } else {
                        free_sja1000dev(dev);
                }
@@ -347,7 +362,7 @@ static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev)
 /*
  * Configure PCMCIA socket
  */
 /*
  * Configure PCMCIA socket
  */
-static void ems_pcmcia_config(struct pcmcia_device *dev)
+static void __devinit ems_pcmcia_config(struct pcmcia_device *dev)
 {
        win_req_t req;
        memreq_t mem;
 {
        win_req_t req;
        memreq_t mem;
index c962029e767398cc36bdb2c2665f35ff1c051d46..8881b1aa57c5310daa18a5a4e3ab26c960195732 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 
 #define DRV_NAME  "esd_pci"
 
 
 #define DRV_NAME  "esd_pci"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+#error This driver does not support Kernel versions < 2.6.21
+#endif
+
 MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu");
 MODULE_DESCRIPTION("Socket-CAN driver for esd PCI/PMC/CPCI/PCIe/PCI104 " \
                   "CAN cards");
 MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu");
 MODULE_DESCRIPTION("Socket-CAN driver for esd PCI/PMC/CPCI/PCIe/PCI104 " \
                   "CAN cards");
@@ -112,14 +117,14 @@ static struct pci_device_id esd_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, esd_pci_tbl);
 
 
 MODULE_DEVICE_TABLE(pci, esd_pci_tbl);
 
-static u8 esd_pci_read_reg(struct net_device *ndev, int port)
+static u8 esd_pci_read_reg(const struct sja1000_priv *priv, int port)
 {
 {
-       return readb((void __iomem *)(ndev->base_addr + port));
+       return readb(priv->reg_base + port);
 }
 
 }
 
-static void esd_pci_write_reg(struct net_device *ndev, int port, u8 val)
+static void esd_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
 {
 {
-       writeb(val, (void __iomem *)(ndev->base_addr + port));
+       writeb(val, priv->reg_base + port);
 }
 
 static void esd_pci_del_chan(struct pci_dev *pdev, struct net_device *ndev)
 }
 
 static void esd_pci_del_chan(struct pci_dev *pdev, struct net_device *ndev)
@@ -144,21 +149,26 @@ static struct net_device * __devinit esd_pci_add_chan(struct pci_dev *pdev,
 
        priv = netdev_priv(ndev);
 
 
        priv = netdev_priv(ndev);
 
-       ndev->base_addr = (unsigned long)base_addr;
+       priv->reg_base = base_addr;
 
        priv->read_reg = esd_pci_read_reg;
        priv->write_reg = esd_pci_write_reg;
 
 
        priv->read_reg = esd_pci_read_reg;
        priv->write_reg = esd_pci_write_reg;
 
-       priv->can.bittiming.clock = ESD_PCI_CAN_CLOCK;
+       priv->can.clock.freq = ESD_PCI_CAN_CLOCK;
 
        priv->ocr = ESD_PCI_OCR;
        priv->cdr = ESD_PCI_CDR;
 
        /* Set and enable PCI interrupts */
 
        priv->ocr = ESD_PCI_OCR;
        priv->cdr = ESD_PCI_CDR;
 
        /* Set and enable PCI interrupts */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
        ndev->irq = pdev->irq;
 
        ndev->irq = pdev->irq;
 
-       dev_dbg(&pdev->dev, "base_addr=%#lx irq=%d\n",
-                       ndev->base_addr, ndev->irq);
+       dev_dbg(&pdev->dev, "reg_base=0x%p irq=%d\n",
+                       priv->reg_base, ndev->irq);
 
        SET_NETDEV_DEV(ndev, &pdev->dev);
 
 
        SET_NETDEV_DEV(ndev, &pdev->dev);
 
index 9f84b4b66c07dc1e0e375a4ca23fa86fa1251813..a86d643dc7e6913414bfa680c9f6d9ced6668c2a 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
@@ -80,16 +81,25 @@ static struct pci_device_id ixxat_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, ixxat_pci_tbl);
 
 
 MODULE_DEVICE_TABLE(pci, ixxat_pci_tbl);
 
-static u8 ixxat_pci_read_reg(struct net_device *ndev, int port)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+static inline void *kzalloc(size_t size, unsigned int __nocast flags)
 {
 {
-       u8 val;
-       val = readb((void __iomem *)(ndev->base_addr + port));
-       return val;
+       void *ret = kmalloc(size, flags);
+       if (ret)
+               memset(ret, 0, size);
+       return ret;
+}
+#endif
+
+static u8 ixxat_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+       return readb(priv->reg_base + port);
 }
 
 }
 
-static void ixxat_pci_write_reg(struct net_device *ndev, int port, u8 val)
+static void ixxat_pci_write_reg(const struct sja1000_priv *priv,
+                               int port, u8 val)
 {
 {
-       writeb(val, (void __iomem *)(ndev->base_addr + port));
+       writeb(val, priv->reg_base + port);
 }
 
 static void ixxat_pci_del_chan(struct pci_dev *pdev, struct net_device *ndev)
 }
 
 static void ixxat_pci_del_chan(struct pci_dev *pdev, struct net_device *ndev)
@@ -114,21 +124,25 @@ static struct net_device *ixxat_pci_add_chan(struct pci_dev *pdev,
 
        priv = netdev_priv(ndev);
 
 
        priv = netdev_priv(ndev);
 
-       ndev->base_addr = (unsigned long)base_addr;
+       priv->reg_base = base_addr;
 
        priv->read_reg = ixxat_pci_read_reg;
        priv->write_reg = ixxat_pci_write_reg;
 
 
        priv->read_reg = ixxat_pci_read_reg;
        priv->write_reg = ixxat_pci_write_reg;
 
-       priv->can.bittiming.clock = IXXAT_PCI_CAN_CLOCK;
+       priv->can.clock.freq = IXXAT_PCI_CAN_CLOCK;
 
        priv->ocr = IXXAT_PCI_OCR;
        priv->cdr = IXXAT_PCI_CDR;
 
 
        priv->ocr = IXXAT_PCI_OCR;
        priv->cdr = IXXAT_PCI_CDR;
 
-       /* Set and enable PCI interrupts */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
        ndev->irq = pdev->irq;
 
        ndev->irq = pdev->irq;
 
-       dev_dbg(&pdev->dev, "base_addr=%#lx irq=%d\n",
-                       ndev->base_addr, ndev->irq);
+       dev_dbg(&pdev->dev, "reg_base=0x%p irq=%d\n",
+                       priv->reg_base, ndev->irq);
 
        SET_NETDEV_DEV(ndev, &pdev->dev);
 
 
        SET_NETDEV_DEV(ndev, &pdev->dev);
 
index fb10907ceaacc85b633e387f79c190b33fb305ca..966f109ac24914778820b2ba50dabfdcaac6e680 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
@@ -53,8 +54,7 @@ MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards");
 MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card");
 MODULE_LICENSE("GPL v2");
 
 MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card");
 MODULE_LICENSE("GPL v2");
 
-#define MAX_NO_OF_CHANNELS        4 /* max no of channels on
-                                      a single card */
+#define MAX_NO_OF_CHANNELS        4 /* max no of channels on a single card */
 
 struct kvaser_pci {
        int channel;
 
 struct kvaser_pci {
        int channel;
@@ -122,38 +122,39 @@ static struct pci_device_id kvaser_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl);
 
 
 MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl);
 
-static u8 kvaser_pci_read_reg(struct net_device *dev, int port)
+static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port)
 {
 {
-       return ioread8((void __iomem *)(dev->base_addr + port));
+       return ioread8(priv->reg_base + port);
 }
 
 }
 
-static void kvaser_pci_write_reg(struct net_device *dev, int port, u8 val)
+static void kvaser_pci_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
 {
 {
-       iowrite8(val, (void __iomem *)(dev->base_addr + port));
+       iowrite8(val, priv->reg_base + port);
 }
 
 static void kvaser_pci_disable_irq(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
        struct kvaser_pci *board = priv->priv;
 }
 
 static void kvaser_pci_disable_irq(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
        struct kvaser_pci *board = priv->priv;
-       u32 tmp;
+       u32 intcsr;
 
        /* Disable interrupts from card */
 
        /* Disable interrupts from card */
-       tmp = ioread32(board->conf_addr + S5920_INTCSR);
-       tmp &= ~INTCSR_ADDON_INTENABLE_M;
-       iowrite32(tmp, board->conf_addr + S5920_INTCSR);
+       intcsr = ioread32(board->conf_addr + S5920_INTCSR);
+       intcsr &= ~INTCSR_ADDON_INTENABLE_M;
+       iowrite32(intcsr, board->conf_addr + S5920_INTCSR);
 }
 
 static void kvaser_pci_enable_irq(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
        struct kvaser_pci *board = priv->priv;
 }
 
 static void kvaser_pci_enable_irq(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
        struct kvaser_pci *board = priv->priv;
-       u32 tmp;
+       u32 tmp_en_io;
 
        /* Enable interrupts from card */
 
        /* Enable interrupts from card */
-       tmp = ioread32(board->conf_addr + S5920_INTCSR);
-       tmp |= INTCSR_ADDON_INTENABLE_M;
-       iowrite32(tmp, board->conf_addr + S5920_INTCSR);
+       tmp_en_io = ioread32(board->conf_addr + S5920_INTCSR);
+       tmp_en_io |= INTCSR_ADDON_INTENABLE_M;
+       iowrite32(tmp_en_io, board->conf_addr + S5920_INTCSR);
 }
 
 static int number_of_sja1000_chip(void __iomem *base_addr)
 }
 
 static int number_of_sja1000_chip(void __iomem *base_addr)
@@ -167,7 +168,6 @@ static int number_of_sja1000_chip(void __iomem *base_addr)
                         (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
                status = ioread8(base_addr +
                                 (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
                         (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
                status = ioread8(base_addr +
                                 (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
-               udelay(10);
                /* check reset bit */
                if (!(status & MOD_RM))
                        break;
                /* check reset bit */
                if (!(status & MOD_RM))
                        break;
@@ -185,8 +185,6 @@ static void kvaser_pci_del_chan(struct net_device *dev)
        if (!dev)
                return;
        priv = netdev_priv(dev);
        if (!dev)
                return;
        priv = netdev_priv(dev);
-       if (!priv)
-               return;
        board = priv->priv;
        if (!board)
                return;
        board = priv->priv;
        if (!board)
                return;
@@ -194,6 +192,9 @@ static void kvaser_pci_del_chan(struct net_device *dev)
        dev_info(&board->pci_dev->dev, "Removing device %s\n",
                 dev->name);
 
        dev_info(&board->pci_dev->dev, "Removing device %s\n",
                 dev->name);
 
+       /* Disable PCI interrupts */
+       kvaser_pci_disable_irq(dev);
+
        for (i = 0; i < board->no_channels - 1; i++) {
                if (board->slave_dev[i]) {
                        dev_info(&board->pci_dev->dev, "Removing device %s\n",
        for (i = 0; i < board->no_channels - 1; i++) {
                if (board->slave_dev[i]) {
                        dev_info(&board->pci_dev->dev, "Removing device %s\n",
@@ -204,10 +205,7 @@ static void kvaser_pci_del_chan(struct net_device *dev)
        }
        unregister_sja1000dev(dev);
 
        }
        unregister_sja1000dev(dev);
 
-       /* Disable PCI interrupts */
-       kvaser_pci_disable_irq(dev);
-
-       pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr);
+       pci_iounmap(board->pci_dev, priv->reg_base);
        pci_iounmap(board->pci_dev, board->conf_addr);
        pci_iounmap(board->pci_dev, board->res_addr);
 
        pci_iounmap(board->pci_dev, board->conf_addr);
        pci_iounmap(board->pci_dev, board->res_addr);
 
@@ -218,7 +216,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
                               struct net_device **master_dev,
                               void __iomem *conf_addr,
                               void __iomem *res_addr,
                               struct net_device **master_dev,
                               void __iomem *conf_addr,
                               void __iomem *res_addr,
-                              unsigned long base_addr)
+                              void __iomem *base_addr)
 {
        struct net_device *dev;
        struct sja1000_priv *priv;
 {
        struct net_device *dev;
        struct sja1000_priv *priv;
@@ -235,10 +233,10 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
        board->pci_dev = pdev;
        board->channel = channel;
 
        board->pci_dev = pdev;
        board->channel = channel;
 
-       /*S5920*/
+       /* S5920 */
        board->conf_addr = conf_addr;
 
        board->conf_addr = conf_addr;
 
-       /*XILINX board wide address*/
+       /* XILINX board wide address */
        board->res_addr = res_addr;
 
        if (channel == 0) {
        board->res_addr = res_addr;
 
        if (channel == 0) {
@@ -250,8 +248,6 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
                   not important */
                iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR);
 
                   not important */
                iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR);
 
-               /* Disable interrupts from card */
-               kvaser_pci_disable_irq(dev);
                /* Enable interrupts from card */
                kvaser_pci_enable_irq(dev);
        } else {
                /* Enable interrupts from card */
                kvaser_pci_enable_irq(dev);
        } else {
@@ -262,22 +258,27 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
                board->xilinx_ver = master_board->xilinx_ver;
        }
 
                board->xilinx_ver = master_board->xilinx_ver;
        }
 
-       dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES;
+       priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES;
 
        priv->read_reg = kvaser_pci_read_reg;
        priv->write_reg = kvaser_pci_write_reg;
 
 
        priv->read_reg = kvaser_pci_read_reg;
        priv->write_reg = kvaser_pci_write_reg;
 
-       priv->can.bittiming.clock = KVASER_PCI_CAN_CLOCK;
+       priv->can.clock.freq = KVASER_PCI_CAN_CLOCK;
 
        priv->ocr = KVASER_PCI_OCR;
        priv->cdr = KVASER_PCI_CDR;
 
 
        priv->ocr = KVASER_PCI_OCR;
        priv->cdr = KVASER_PCI_CDR;
 
-       /* Register and setup interrupt handling */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
        dev->irq = pdev->irq;
        dev->irq = pdev->irq;
+
        init_step = 4;
 
        init_step = 4;
 
-       dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n",
-                dev->base_addr, board->conf_addr, dev->irq);
+       dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n",
+                priv->reg_base, board->conf_addr, dev->irq);
 
        SET_NETDEV_DEV(dev, &pdev->dev);
 
 
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -323,14 +324,14 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
        if (err)
                goto failure_release_pci;
 
        if (err)
                goto failure_release_pci;
 
-       /*S5920*/
+       /* S5920 */
        conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE);
        if (conf_addr == NULL) {
                err = -ENODEV;
        conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE);
        if (conf_addr == NULL) {
                err = -ENODEV;
-               goto failure_iounmap;
+               goto failure_release_regions;
        }
 
        }
 
-       /*XILINX board wide address*/
+       /* XILINX board wide address */
        res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE);
        if (res_addr == NULL) {
                err = -ENOMEM;
        res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE);
        if (res_addr == NULL) {
                err = -ENOMEM;
@@ -352,7 +353,7 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
        for (i = 0; i < no_channels; i++) {
                err = kvaser_pci_add_chan(pdev, i, &master_dev,
                                          conf_addr, res_addr,
        for (i = 0; i < no_channels; i++) {
                err = kvaser_pci_add_chan(pdev, i, &master_dev,
                                          conf_addr, res_addr,
-                                         (unsigned long)base_addr);
+                                         base_addr);
                if (err)
                        goto failure_cleanup;
        }
                if (err)
                        goto failure_cleanup;
        }
@@ -370,13 +371,14 @@ failure_cleanup:
        kvaser_pci_del_chan(master_dev);
 
 failure_iounmap:
        kvaser_pci_del_chan(master_dev);
 
 failure_iounmap:
-       if (conf_addr == NULL)
+       if (conf_addr != NULL)
                pci_iounmap(pdev, conf_addr);
                pci_iounmap(pdev, conf_addr);
-       if (res_addr == NULL)
+       if (res_addr != NULL)
                pci_iounmap(pdev, res_addr);
                pci_iounmap(pdev, res_addr);
-       if (base_addr == NULL)
+       if (base_addr != NULL)
                pci_iounmap(pdev, base_addr);
 
                pci_iounmap(pdev, base_addr);
 
+failure_release_regions:
        pci_release_regions(pdev);
 
 failure_release_pci:
        pci_release_regions(pdev);
 
 failure_release_pci:
index 22d69e459dfb66f3ee0f9d351a7507a6fc481ce7..9decb90ba86881e41e437ae6af4a73e9b041b46c 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #include <linux/io.h>
 #else
 
 #define DRV_NAME  "peak_pci"
 
 
 #define DRV_NAME  "peak_pci"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+#error This driver does not support Kernel versions < 2.6.23
+#endif
+
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI cards");
 MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI CAN card");
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI cards");
 MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI CAN card");
@@ -81,23 +86,19 @@ static struct pci_device_id peak_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
 
 
 MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
 
-static u8 peak_pci_read_reg(struct net_device *dev, int port)
+static u8 peak_pci_read_reg(const struct sja1000_priv *priv, int port)
 {
 {
-       u8 val;
-       val = readb((const volatile void __iomem *)
-                   (dev->base_addr + (port << 2)));
-       return val;
+       return readb(priv->reg_base + (port << 2));
 }
 
 }
 
-static void peak_pci_write_reg(struct net_device *dev, int port, u8 val)
+static void peak_pci_write_reg(const struct sja1000_priv *priv,
+                              int port, u8 val)
 {
 {
-       writeb(val, (volatile void __iomem *)
-              (dev->base_addr + (port << 2)));
+       writeb(val, priv->reg_base + (port << 2));
 }
 
 }
 
-static void peak_pci_post_irq(struct net_device *dev)
+static void peak_pci_post_irq(const struct sja1000_priv *priv)
 {
 {
-       struct sja1000_priv *priv = netdev_priv(dev);
        struct peak_pci *board = priv->priv;
        u16 icr_low;
 
        struct peak_pci *board = priv->priv;
        u16 icr_low;
 
@@ -140,7 +141,7 @@ static void peak_pci_del_chan(struct net_device *dev, int init_step)
                        icr_high &= ~0x0002;
                writew(icr_high, board->conf_addr + PITA_ICR + 2);
        case 3:
                        icr_high &= ~0x0002;
                writew(icr_high, board->conf_addr + PITA_ICR + 2);
        case 3:
-               iounmap((void *)dev->base_addr);
+               iounmap(priv->reg_base);
        case 2:
                if (board->channel != PEAK_PCI_SLAVE)
                        iounmap((void *)board->conf_addr);
        case 2:
                if (board->channel != PEAK_PCI_SLAVE)
                        iounmap((void *)board->conf_addr);
@@ -206,8 +207,8 @@ static int peak_pci_add_chan(struct pci_dev *pdev, int channel,
        if (channel == PEAK_PCI_SLAVE)
                addr += PCI_PORT_SIZE;
 
        if (channel == PEAK_PCI_SLAVE)
                addr += PCI_PORT_SIZE;
 
-       dev->base_addr = (unsigned long)ioremap(addr, PCI_PORT_SIZE);
-       if (dev->base_addr == 0) {
+       priv->reg_base = ioremap(addr, PCI_PORT_SIZE);
+       if (priv->reg_base == 0) {
                err = -ENOMEM;
                goto failure;
        }
                err = -ENOMEM;
                goto failure;
        }
@@ -217,7 +218,7 @@ static int peak_pci_add_chan(struct pci_dev *pdev, int channel,
        priv->write_reg = peak_pci_write_reg;
        priv->post_irq = peak_pci_post_irq;
 
        priv->write_reg = peak_pci_write_reg;
        priv->post_irq = peak_pci_post_irq;
 
-       priv->can.bittiming.clock = PEAK_PCI_CAN_CLOCK;
+       priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
 
        priv->ocr = PEAK_PCI_OCR;
 
 
        priv->ocr = PEAK_PCI_OCR;
 
@@ -226,7 +227,12 @@ static int peak_pci_add_chan(struct pci_dev *pdev, int channel,
        else
                priv->cdr = PEAK_PCI_CDR_SINGLE;
 
        else
                priv->cdr = PEAK_PCI_CDR_SINGLE;
 
-       /* Register and setup interrupt handling */
+       /* Setup interrupt handling */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
        dev->irq = pdev->irq;
        icr_high = readw(board->conf_addr + PITA_ICR + 2);
        if (channel == PEAK_PCI_SLAVE)
        dev->irq = pdev->irq;
        icr_high = readw(board->conf_addr + PITA_ICR + 2);
        if (channel == PEAK_PCI_SLAVE)
@@ -249,8 +255,8 @@ static int peak_pci_add_chan(struct pci_dev *pdev, int channel,
        if (channel != PEAK_PCI_SLAVE)
                *master_dev = dev;
 
        if (channel != PEAK_PCI_SLAVE)
                *master_dev = dev;
 
-       printk(KERN_INFO "%s: %s at base_addr=%#lx conf_addr=%p irq=%d\n",
-              DRV_NAME, dev->name, dev->base_addr, board->conf_addr, dev->irq);
+       printk(KERN_INFO "%s: %s at reg_base=0x%p conf_addr=%p irq=%d\n",
+              DRV_NAME, dev->name, priv->reg_base, board->conf_addr, dev->irq);
 
        return 0;
 
 
        return 0;
 
index b7414b2186974d6b4ba3c41a6edcf7f5b6dc49e7..325a8238ed08c9a0a40c25a46ee4b0e293b7877a 100644 (file)
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 #include <linux/io.h>
 
 #include "sja1000.h"
 
 #define DRV_NAME "pipcan"
 
 #include <linux/io.h>
 
 #include "sja1000.h"
 
 #define DRV_NAME "pipcan"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#error This driver does not support Kernel versions < 2.6.20
+#endif
+
 MODULE_AUTHOR("David Müller <d.mueller@elsoft.ch>");
 MODULE_DESCRIPTION("Socket-CAN driver for MPL PIPCAN module");
 MODULE_SUPPORTED_DEVICE("MPL PIPCAN module");
 MODULE_AUTHOR("David Müller <d.mueller@elsoft.ch>");
 MODULE_DESCRIPTION("Socket-CAN driver for MPL PIPCAN module");
 MODULE_SUPPORTED_DEVICE("MPL PIPCAN module");
@@ -44,14 +49,14 @@ MODULE_LICENSE("GPL v2");
 #define PIPCAN_RES        (0x804)
 #define PIPCAN_RST        (0x805)
 
 #define PIPCAN_RES        (0x804)
 #define PIPCAN_RST        (0x805)
 
-static u8 pc_read_reg(struct net_device *dev, int reg)
+static u8 pc_read_reg(const struct sja1000_priv *priv, int reg)
 {
 {
-       return inb(dev->base_addr + reg);
+  return inb((unsigned long)priv->reg_base + reg);
 }
 
 }
 
-static void pc_write_reg(struct net_device *dev, int reg, u8 val)
+static void pc_write_reg(const struct sja1000_priv *priv, int reg, u8 val)
 {
 {
-       outb(val, dev->base_addr + reg);
+  outb(val, (unsigned long)priv->reg_base + reg);
 }
 
 static int __init pc_probe(struct platform_device *pdev)
 }
 
 static int __init pc_probe(struct platform_device *pdev)
@@ -80,12 +85,18 @@ static int __init pc_probe(struct platform_device *pdev)
 
        priv->read_reg = pc_read_reg;
        priv->write_reg = pc_write_reg;
 
        priv->read_reg = pc_read_reg;
        priv->write_reg = pc_write_reg;
-       priv->can.bittiming.clock = PIPCAN_CAN_CLOCK;
+       priv->can.clock.freq = PIPCAN_CAN_CLOCK;
        priv->ocr = PIPCAN_OCR;
        priv->cdr = PIPCAN_CDR;
        priv->ocr = PIPCAN_OCR;
        priv->cdr = PIPCAN_CDR;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
 
        dev->irq = irq;
        dev->base_addr = res->start;
 
        dev->irq = irq;
        dev->base_addr = res->start;
+       priv->reg_base = (void __iomem *)res->start;
 
        dev_set_drvdata(&pdev->dev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        dev_set_drvdata(&pdev->dev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
index f9244ca3068e450b3752e8908cf3210d337f6491..5e1605baf54634022816a7fce8c238539755f97e 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
+#include <socketcan/can/dev.h>
 
 #include "sja1000.h"
 
 
 #include "sja1000.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
 RCSID("$Id: sja1000.c 531 2007-10-19 07:38:29Z hartkopp $");
 
 #define DRV_NAME "sja1000"
 
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
 MODULE_LICENSE("Dual BSD/GPL");
 RCSID("$Id: sja1000.c 531 2007-10-19 07:38:29Z hartkopp $");
 
 #define DRV_NAME "sja1000"
 
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION(DRV_NAME " CAN netdevice driver");
+MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver");
 
 static struct can_bittiming_const sja1000_bittiming_const = {
 
 static struct can_bittiming_const sja1000_bittiming_const = {
+       .name = DRV_NAME,
        .tseg1_min = 1,
        .tseg1_max = 16,
        .tseg2_min = 1,
        .tseg1_min = 1,
        .tseg1_max = 16,
        .tseg2_min = 1,
@@ -92,65 +93,60 @@ static int sja1000_probe_chip(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
-       if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) {
-               printk(KERN_INFO "%s: probing @0x%lX failed\n",
-                      DRV_NAME, dev->base_addr);
+       if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) {
+               dev_info(ND2D(dev), "probing @0x%p failed\n",
+                        priv->reg_base);
                return 0;
        }
                return 0;
        }
-       return 1;
+       return -1;
 }
 
 }
 
-static int set_reset_mode(struct net_device *dev)
+static void set_reset_mode(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 {
        struct sja1000_priv *priv = netdev_priv(dev);
-       unsigned char status = priv->read_reg(dev, REG_MOD);
+       unsigned char status = priv->read_reg(priv, REG_MOD);
        int i;
 
        /* disable interrupts */
        int i;
 
        /* disable interrupts */
-       priv->write_reg(dev, REG_IER, IRQ_OFF);
+       priv->write_reg(priv, REG_IER, IRQ_OFF);
 
        for (i = 0; i < 100; i++) {
                /* check reset bit */
                if (status & MOD_RM) {
                        priv->can.state = CAN_STATE_STOPPED;
 
        for (i = 0; i < 100; i++) {
                /* check reset bit */
                if (status & MOD_RM) {
                        priv->can.state = CAN_STATE_STOPPED;
-                       return 0;
+                       return;
                }
 
                }
 
-               priv->write_reg(dev, REG_MOD, MOD_RM);  /* reset chip */
-               status = priv->read_reg(dev, REG_MOD);
+               priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */
                udelay(10);
                udelay(10);
+               status = priv->read_reg(priv, REG_MOD);
        }
 
        dev_err(ND2D(dev), "setting SJA1000 into reset mode failed!\n");
        }
 
        dev_err(ND2D(dev), "setting SJA1000 into reset mode failed!\n");
-       return 1;
-
 }
 
 }
 
-static int set_normal_mode(struct net_device *dev)
+static void set_normal_mode(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 {
        struct sja1000_priv *priv = netdev_priv(dev);
-       unsigned char status = priv->read_reg(dev, REG_MOD);
+       unsigned char status = priv->read_reg(priv, REG_MOD);
        int i;
 
        for (i = 0; i < 100; i++) {
                /* check reset bit */
                if ((status & MOD_RM) == 0) {
        int i;
 
        for (i = 0; i < 100; i++) {
                /* check reset bit */
                if ((status & MOD_RM) == 0) {
-                       priv->can.state = CAN_STATE_ACTIVE;
+                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
                        /* enable all interrupts */
                        /* enable all interrupts */
-                       priv->write_reg(dev, REG_IER, IRQ_ALL);
-
-                       return 0;
+                       priv->write_reg(priv, REG_IER, IRQ_ALL);
+                       return;
                }
 
                /* set chip to normal mode */
                }
 
                /* set chip to normal mode */
-               priv->write_reg(dev, REG_MOD, 0x00);
-               status = priv->read_reg(dev, REG_MOD);
+               priv->write_reg(priv, REG_MOD, 0x00);
                udelay(10);
                udelay(10);
+               status = priv->read_reg(priv, REG_MOD);
        }
 
        dev_err(ND2D(dev), "setting SJA1000 into normal mode failed!\n");
        }
 
        dev_err(ND2D(dev), "setting SJA1000 into normal mode failed!\n");
-       return 1;
-
 }
 
 static void sja1000_start(struct net_device *dev)
 }
 
 static void sja1000_start(struct net_device *dev)
@@ -162,9 +158,9 @@ static void sja1000_start(struct net_device *dev)
                set_reset_mode(dev);
 
        /* Clear error counters and error code capture */
                set_reset_mode(dev);
 
        /* Clear error counters and error code capture */
-       priv->write_reg(dev, REG_TXERR, 0x0);
-       priv->write_reg(dev, REG_RXERR, 0x0);
-       priv->read_reg(dev, REG_ECC);
+       priv->write_reg(priv, REG_TXERR, 0x0);
+       priv->write_reg(priv, REG_RXERR, 0x0);
+       priv->read_reg(priv, REG_ECC);
 
        /* leave reset mode */
        set_normal_mode(dev);
 
        /* leave reset mode */
        set_normal_mode(dev);
@@ -174,11 +170,11 @@ static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
+       if (!priv->open_time)
+               return -EINVAL;
+
        switch (mode) {
        case CAN_MODE_START:
        switch (mode) {
        case CAN_MODE_START:
-               if (!priv->open_time)
-                       return -EINVAL;
-
                sja1000_start(dev);
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
                sja1000_start(dev);
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
@@ -191,43 +187,6 @@ static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
        return 0;
 }
 
        return 0;
 }
 
-static int sja1000_get_state(struct net_device *dev, enum can_state *state)
-{
-       struct sja1000_priv *priv = netdev_priv(dev);
-       u8 status;
-
-       /* FIXME: inspecting the status register to get the current state
-        * is not really necessary, because state changes are handled by
-        * in the ISR and the variable priv->can.state gets updated. The
-        * CAN devicde interface needs fixing!
-        */
-
-       spin_lock_irq(&priv->can.irq_lock);
-
-       if (priv->can.state == CAN_STATE_STOPPED) {
-               *state =  CAN_STATE_STOPPED;
-       } else {
-               status = priv->read_reg(dev, REG_SR);
-               if (status & SR_BS)
-                       *state = CAN_STATE_BUS_OFF;
-               else if (status & SR_ES) {
-                       if (priv->read_reg(dev, REG_TXERR) > 127 ||
-                           priv->read_reg(dev, REG_RXERR) > 127)
-                               *state = CAN_STATE_BUS_PASSIVE;
-                       else
-                               *state = CAN_STATE_BUS_WARNING;
-               } else
-                       *state = CAN_STATE_ACTIVE;
-       }
-       /* Check state */
-       if (*state != priv->can.state)
-               dev_err(ND2D(dev),
-                       "Oops, state mismatch: hard %d != soft %d\n",
-                       *state, priv->can.state);
-       spin_unlock_irq(&priv->can.irq_lock);
-       return 0;
-}
-
 static int sja1000_set_bittiming(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 static int sja1000_set_bittiming(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
@@ -236,13 +195,15 @@ static int sja1000_set_bittiming(struct net_device *dev)
 
        btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
        btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
 
        btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
        btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
-               (((bt->phase_seg2 - 1) & 0x7) << 4) |
-         ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) << 7);
+               (((bt->phase_seg2 - 1) & 0x7) << 4);
+       if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+               btr1 |= 0x80;
 
 
-       dev_info(ND2D(dev), "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
+       dev_info(ND2D(dev),
+                "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
 
 
-       priv->write_reg(dev, REG_BTR0, btr0);
-       priv->write_reg(dev, REG_BTR1, btr1);
+       priv->write_reg(priv, REG_BTR0, btr0);
+       priv->write_reg(priv, REG_BTR1, btr1);
 
        return 0;
 }
 
        return 0;
 }
@@ -260,20 +221,20 @@ static void chipset_init(struct net_device *dev)
        struct sja1000_priv *priv = netdev_priv(dev);
 
        /* set clock divider and output control register */
        struct sja1000_priv *priv = netdev_priv(dev);
 
        /* set clock divider and output control register */
-       priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN);
+       priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN);
 
        /* set acceptance filter (accept all) */
 
        /* set acceptance filter (accept all) */
-       priv->write_reg(dev, REG_ACCC0, 0x00);
-       priv->write_reg(dev, REG_ACCC1, 0x00);
-       priv->write_reg(dev, REG_ACCC2, 0x00);
-       priv->write_reg(dev, REG_ACCC3, 0x00);
+       priv->write_reg(priv, REG_ACCC0, 0x00);
+       priv->write_reg(priv, REG_ACCC1, 0x00);
+       priv->write_reg(priv, REG_ACCC2, 0x00);
+       priv->write_reg(priv, REG_ACCC3, 0x00);
 
 
-       priv->write_reg(dev, REG_ACCM0, 0xFF);
-       priv->write_reg(dev, REG_ACCM1, 0xFF);
-       priv->write_reg(dev, REG_ACCM2, 0xFF);
-       priv->write_reg(dev, REG_ACCM3, 0xFF);
+       priv->write_reg(priv, REG_ACCM0, 0xFF);
+       priv->write_reg(priv, REG_ACCM1, 0xFF);
+       priv->write_reg(priv, REG_ACCM2, 0xFF);
+       priv->write_reg(priv, REG_ACCM3, 0xFF);
 
 
-       priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
+       priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
 }
 
 /*
 }
 
 /*
@@ -308,27 +269,27 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (id & CAN_EFF_FLAG) {
                fi |= FI_FF;
                dreg = EFF_BUF;
        if (id & CAN_EFF_FLAG) {
                fi |= FI_FF;
                dreg = EFF_BUF;
-               priv->write_reg(dev, REG_FI, fi);
-               priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
-               priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8));
-               priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5);
-               priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3);
+               priv->write_reg(priv, REG_FI, fi);
+               priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
+               priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8));
+               priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5);
+               priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3);
        } else {
                dreg = SFF_BUF;
        } else {
                dreg = SFF_BUF;
-               priv->write_reg(dev, REG_FI, fi);
-               priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3);
-               priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5);
+               priv->write_reg(priv, REG_FI, fi);
+               priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3);
+               priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5);
        }
 
        for (i = 0; i < dlc; i++)
        }
 
        for (i = 0; i < dlc; i++)
-               priv->write_reg(dev, dreg++, cf->data[i]);
+               priv->write_reg(priv, dreg++, cf->data[i]);
 
        stats->tx_bytes += dlc;
        dev->trans_start = jiffies;
 
        can_put_echo_skb(skb, dev, 0);
 
 
        stats->tx_bytes += dlc;
        dev->trans_start = jiffies;
 
        can_put_echo_skb(skb, dev, 0);
 
-       priv->write_reg(dev, REG_CMR, CMD_TR);
+       priv->write_reg(priv, REG_CMR, CMD_TR);
 
        return 0;
 }
 
        return 0;
 }
@@ -355,22 +316,22 @@ static void sja1000_rx(struct net_device *dev)
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
 
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
 
-       fi = priv->read_reg(dev, REG_FI);
+       fi = priv->read_reg(priv, REG_FI);
        dlc = fi & 0x0F;
 
        if (fi & FI_FF) {
                /* extended frame format (EFF) */
                dreg = EFF_BUF;
        dlc = fi & 0x0F;
 
        if (fi & FI_FF) {
                /* extended frame format (EFF) */
                dreg = EFF_BUF;
-               id = (priv->read_reg(dev, REG_ID1) << (5 + 16))
-                   | (priv->read_reg(dev, REG_ID2) << (5 + 8))
-                   | (priv->read_reg(dev, REG_ID3) << 5)
-                   | (priv->read_reg(dev, REG_ID4) >> 3);
+               id = (priv->read_reg(priv, REG_ID1) << (5 + 16))
+                   | (priv->read_reg(priv, REG_ID2) << (5 + 8))
+                   | (priv->read_reg(priv, REG_ID3) << 5)
+                   | (priv->read_reg(priv, REG_ID4) >> 3);
                id |= CAN_EFF_FLAG;
        } else {
                /* standard frame format (SFF) */
                dreg = SFF_BUF;
                id |= CAN_EFF_FLAG;
        } else {
                /* standard frame format (SFF) */
                dreg = SFF_BUF;
-               id = (priv->read_reg(dev, REG_ID1) << 3)
-                   | (priv->read_reg(dev, REG_ID2) >> 5);
+               id = (priv->read_reg(priv, REG_ID1) << 3)
+                   | (priv->read_reg(priv, REG_ID2) >> 5);
        }
 
        if (fi & FI_RTR)
        }
 
        if (fi & FI_RTR)
@@ -381,13 +342,13 @@ static void sja1000_rx(struct net_device *dev)
        cf->can_id = id;
        cf->can_dlc = dlc;
        for (i = 0; i < dlc; i++)
        cf->can_id = id;
        cf->can_dlc = dlc;
        for (i = 0; i < dlc; i++)
-               cf->data[i] = priv->read_reg(dev, dreg++);
+               cf->data[i] = priv->read_reg(priv, dreg++);
 
        while (i < 8)
                cf->data[i++] = 0;
 
        /* release receive buffer */
 
        while (i < 8)
                cf->data[i++] = 0;
 
        /* release receive buffer */
-       priv->write_reg(dev, REG_CMR, CMD_RRB);
+       priv->write_reg(priv, REG_CMR, CMD_RRB);
 
        netif_rx(skb);
 
 
        netif_rx(skb);
 
@@ -424,13 +385,13 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                dev_dbg(ND2D(dev), "data overrun interrupt\n");
                cf->can_id |= CAN_ERR_CRTL;
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                dev_dbg(ND2D(dev), "data overrun interrupt\n");
                cf->can_id |= CAN_ERR_CRTL;
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-               priv->can.can_stats.data_overrun++;
-               priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */
+               stats->rx_over_errors++;
+               stats->rx_errors++;
+               priv->write_reg(priv, REG_CMR, CMD_CDO);        /* clear bit */
        }
 
        if (isrc & IRQ_EI) {
                /* error warning interrupt */
        }
 
        if (isrc & IRQ_EI) {
                /* error warning interrupt */
-               priv->can.can_stats.error_warning++;
                dev_dbg(ND2D(dev), "error warning interrupt\n");
 
                if (status & SR_BS) {
                dev_dbg(ND2D(dev), "error warning interrupt\n");
 
                if (status & SR_BS) {
@@ -438,14 +399,16 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                        cf->can_id |= CAN_ERR_BUSOFF;
                        can_bus_off(dev);
                } else if (status & SR_ES) {
                        cf->can_id |= CAN_ERR_BUSOFF;
                        can_bus_off(dev);
                } else if (status & SR_ES) {
-                       state = CAN_STATE_BUS_WARNING;
+                       state = CAN_STATE_ERROR_WARNING;
                } else
                } else
-                       state = CAN_STATE_ACTIVE;
+                       state = CAN_STATE_ERROR_ACTIVE;
        }
        if (isrc & IRQ_BEI) {
                /* bus error interrupt */
                priv->can.can_stats.bus_error++;
        }
        if (isrc & IRQ_BEI) {
                /* bus error interrupt */
                priv->can.can_stats.bus_error++;
-               ecc = priv->read_reg(dev, REG_ECC);
+               stats->rx_errors++;
+
+               ecc = priv->read_reg(priv, REG_ECC);
 
                cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 
 
                cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 
@@ -471,34 +434,37 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
        if (isrc & IRQ_EPI) {
                /* error passive interrupt */
                dev_dbg(ND2D(dev), "error passive interrupt\n");
        if (isrc & IRQ_EPI) {
                /* error passive interrupt */
                dev_dbg(ND2D(dev), "error passive interrupt\n");
-               priv->can.can_stats.error_passive++;
                if (status & SR_ES)
                if (status & SR_ES)
-                       state = CAN_STATE_BUS_PASSIVE;
+                       state = CAN_STATE_ERROR_PASSIVE;
                else
                else
-                       state = CAN_STATE_ACTIVE;
+                       state = CAN_STATE_ERROR_ACTIVE;
        }
        if (isrc & IRQ_ALI) {
                /* arbitration lost interrupt */
                dev_dbg(ND2D(dev), "arbitration lost interrupt\n");
        }
        if (isrc & IRQ_ALI) {
                /* arbitration lost interrupt */
                dev_dbg(ND2D(dev), "arbitration lost interrupt\n");
-               alc = priv->read_reg(dev, REG_ALC);
+               alc = priv->read_reg(priv, REG_ALC);
                priv->can.can_stats.arbitration_lost++;
                priv->can.can_stats.arbitration_lost++;
+               stats->rx_errors++;
                cf->can_id |= CAN_ERR_LOSTARB;
                cf->data[0] = alc & 0x1f;
        }
 
                cf->can_id |= CAN_ERR_LOSTARB;
                cf->data[0] = alc & 0x1f;
        }
 
-       if (state != priv->can.state && (state == CAN_STATE_BUS_WARNING ||
-                                        state == CAN_STATE_BUS_PASSIVE)) {
-               uint8_t rxerr = priv->read_reg(dev, REG_RXERR);
-               uint8_t txerr = priv->read_reg(dev, REG_TXERR);
+       if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
+                                        state == CAN_STATE_ERROR_PASSIVE)) {
+               uint8_t rxerr = priv->read_reg(priv, REG_RXERR);
+               uint8_t txerr = priv->read_reg(priv, REG_TXERR);
                cf->can_id |= CAN_ERR_CRTL;
                cf->can_id |= CAN_ERR_CRTL;
-               if (state == CAN_STATE_BUS_WARNING)
+               if (state == CAN_STATE_ERROR_WARNING) {
+                       priv->can.can_stats.error_warning++;
                        cf->data[1] = (txerr > rxerr) ?
                                CAN_ERR_CRTL_TX_WARNING :
                                CAN_ERR_CRTL_RX_WARNING;
                        cf->data[1] = (txerr > rxerr) ?
                                CAN_ERR_CRTL_TX_WARNING :
                                CAN_ERR_CRTL_RX_WARNING;
-               else
+               } else {
+                       priv->can.can_stats.error_passive++;
                        cf->data[1] = (txerr > rxerr) ?
                                CAN_ERR_CRTL_TX_PASSIVE :
                                CAN_ERR_CRTL_RX_PASSIVE;
                        cf->data[1] = (txerr > rxerr) ?
                                CAN_ERR_CRTL_TX_PASSIVE :
                                CAN_ERR_CRTL_RX_PASSIVE;
+               }
        }
 
        priv->can.state = state;
        }
 
        priv->can.state = state;
@@ -529,20 +495,19 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
        int n = 0;
 
        /* Shared interrupts and IRQ off? */
        int n = 0;
 
        /* Shared interrupts and IRQ off? */
-       if (priv->read_reg(dev, REG_IER) == IRQ_OFF)
+       if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
                return IRQ_NONE;
 
        if (priv->pre_irq)
                return IRQ_NONE;
 
        if (priv->pre_irq)
-               priv->pre_irq(dev);
+               priv->pre_irq(priv);
 
 
-       while ((isrc = priv->read_reg(dev, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
+       while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
                n++;
                n++;
-               status = priv->read_reg(dev, REG_SR);
+               status = priv->read_reg(priv, REG_SR);
+
+               if (isrc & IRQ_WUI)
+                       dev_warn(ND2D(dev), "wakeup interrupt\n");
 
 
-               if (isrc & IRQ_WUI) {
-                       /* wake-up interrupt */
-                       priv->can.can_stats.wakeup++;
-               }
                if (isrc & IRQ_TI) {
                        /* transmission complete interrupt */
                        stats->tx_packets++;
                if (isrc & IRQ_TI) {
                        /* transmission complete interrupt */
                        stats->tx_packets++;
@@ -553,7 +518,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
                        /* receive interrupt */
                        while (status & SR_RBS) {
                                sja1000_rx(dev);
                        /* receive interrupt */
                        while (status & SR_RBS) {
                                sja1000_rx(dev);
-                               status = priv->read_reg(dev, REG_SR);
+                               status = priv->read_reg(priv, REG_SR);
                        }
                }
                if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
                        }
                }
                if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
@@ -564,7 +529,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
        }
 
        if (priv->post_irq)
        }
 
        if (priv->post_irq)
-               priv->post_irq(dev);
+               priv->post_irq(priv);
 
        if (n >= SJA1000_MAX_IRQ)
                dev_dbg(ND2D(dev), "%d messages handled in ISR", n);
 
        if (n >= SJA1000_MAX_IRQ)
                dev_dbg(ND2D(dev), "%d messages handled in ISR", n);
@@ -581,22 +546,19 @@ static int sja1000_open(struct net_device *dev)
        /* set chip into reset mode */
        set_reset_mode(dev);
 
        /* set chip into reset mode */
        set_reset_mode(dev);
 
-       /* determine and set bittime */
-       err = can_set_bittiming(dev);
+       /* common open */
+       err = open_candev(dev);
        if (err)
                return err;
 
        /* register interrupt handler, if not done by the device driver */
        if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) {
        if (err)
                return err;
 
        /* register interrupt handler, if not done by the device driver */
        if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
-               err = request_irq(dev->irq, &sja1000_interrupt, SA_SHIRQ,
-                                 dev->name, (void *)dev);
-#else
-               err = request_irq(dev->irq, &sja1000_interrupt, IRQF_SHARED,
+               err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags,
                                  dev->name, (void *)dev);
                                  dev->name, (void *)dev);
-#endif
-               if (err)
+               if (err) {
+                       close_candev(dev);
                        return -EAGAIN;
                        return -EAGAIN;
+               }
        }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
@@ -617,14 +579,16 @@ static int sja1000_close(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
-       set_reset_mode(dev);
        netif_stop_queue(dev);
        netif_stop_queue(dev);
-       priv->open_time = 0;
-       can_close_cleanup(dev);
+       set_reset_mode(dev);
 
        if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER))
                free_irq(dev->irq, (void *)dev);
 
 
        if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER))
                free_irq(dev->irq, (void *)dev);
 
+       close_candev(dev);
+
+       priv->open_time = 0;
+
        return 0;
 }
 
        return 0;
 }
 
@@ -638,7 +602,11 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
                return NULL;
 
        priv = netdev_priv(dev);
                return NULL;
 
        priv = netdev_priv(dev);
+
        priv->dev = dev;
        priv->dev = dev;
+       priv->can.bittiming_const = &sja1000_bittiming_const;
+       priv->can.do_set_bittiming = sja1000_set_bittiming;
+       priv->can.do_set_mode = sja1000_set_mode;
 
        if (sizeof_priv)
                priv->priv = (void *)priv + sizeof(struct sja1000_priv);
 
        if (sizeof_priv)
                priv->priv = (void *)priv + sizeof(struct sja1000_priv);
@@ -655,22 +623,17 @@ EXPORT_SYMBOL_GPL(free_sja1000dev);
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
 static const struct net_device_ops sja1000_netdev_ops = {
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
 static const struct net_device_ops sja1000_netdev_ops = {
-       .ndo_open               = sja1000_open,
-       .ndo_stop               = sja1000_close,
-       .ndo_start_xmit         = sja1000_start_xmit,
+       .ndo_open               = sja1000_open,
+       .ndo_stop               = sja1000_close,
+       .ndo_start_xmit         = sja1000_start_xmit,
 };
 #endif
 
 int register_sja1000dev(struct net_device *dev)
 {
 };
 #endif
 
 int register_sja1000dev(struct net_device *dev)
 {
-       struct sja1000_priv *priv = netdev_priv(dev);
-       int err;
-
        if (!sja1000_probe_chip(dev))
                return -ENODEV;
 
        if (!sja1000_probe_chip(dev))
                return -ENODEV;
 
-       dev->flags |= IFF_ECHO; /* we support local echo */
-
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
        dev->netdev_ops = &sja1000_netdev_ops;
 #else
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
        dev->netdev_ops = &sja1000_netdev_ops;
 #else
@@ -679,23 +642,12 @@ int register_sja1000dev(struct net_device *dev)
        dev->hard_start_xmit = sja1000_start_xmit;
 #endif
 
        dev->hard_start_xmit = sja1000_start_xmit;
 #endif
 
-       priv->can.bittiming_const = &sja1000_bittiming_const;
-       priv->can.do_set_bittiming = sja1000_set_bittiming;
-       priv->can.do_get_state = sja1000_get_state;
-       priv->can.do_set_mode = sja1000_set_mode;
-       priv->dev = dev;
-
-       err = register_candev(dev);
-       if (err) {
-               printk(KERN_INFO
-                      "%s: registering netdev failed\n", DRV_NAME);
-               free_netdev(dev);
-               return err;
-       }
+       dev->flags |= IFF_ECHO; /* we support local echo */
 
        set_reset_mode(dev);
        chipset_init(dev);
 
        set_reset_mode(dev);
        chipset_init(dev);
-       return 0;
+
+       return register_candev(dev);
 }
 EXPORT_SYMBOL_GPL(register_sja1000dev);
 
 }
 EXPORT_SYMBOL_GPL(register_sja1000dev);
 
index c5295771e48b76db88b903b0140ddf044b531023..7a35f4c3f98dbd07f2e1217e0133b393b41a4718 100644 (file)
@@ -1,6 +1,4 @@
 /*
 /*
- * $Id: sja1000.h 505 2007-09-30 13:32:41Z hartkopp $
- *
  * sja1000.h -  Philips SJA1000 network device driver
  *
  * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
  * sja1000.h -  Philips SJA1000 network device driver
  *
  * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33,
@@ -49,9 +47,8 @@
 #ifndef SJA1000_DEV_H
 #define SJA1000_DEV_H
 
 #ifndef SJA1000_DEV_H
 #define SJA1000_DEV_H
 
-#include <linux/version.h>
-#include <linux/can/dev.h>
-#include <linux/can/platform/sja1000.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/platform/sja1000.h>
 
 #define SJA1000_MAX_IRQ 20     /* max. number of interrupts handled in ISR */
 
 
 #define SJA1000_MAX_IRQ 20     /* max. number of interrupts handled in ISR */
 
  * SJA1000 private data structure
  */
 struct sja1000_priv {
  * SJA1000 private data structure
  */
 struct sja1000_priv {
-       struct can_priv can;    /* must be the first member! */
-       long open_time;
+       struct can_priv can;    /* must be the first member */
+       int open_time;
        struct sk_buff *echo_skb;
 
        struct sk_buff *echo_skb;
 
-       u8 (*read_reg) (struct net_device *dev, int reg);
-       void (*write_reg) (struct net_device *dev, int reg, u8 val);
-       void (*pre_irq) (struct net_device *dev);
-       void (*post_irq) (struct net_device *dev);
+       /* the lower-layer is responsible for appropriate locking */
+       u8 (*read_reg) (const struct sja1000_priv *priv, int reg);
+       void (*write_reg) (const struct sja1000_priv *priv, int reg, u8 val);
+       void (*pre_irq) (const struct sja1000_priv *priv);
+       void (*post_irq) (const struct sja1000_priv *priv);
 
        void *priv;             /* for board-specific data */
        struct net_device *dev;
 
 
        void *priv;             /* for board-specific data */
        struct net_device *dev;
 
-       u8 ocr;
-       u8 cdr;
-       u32 flags;
+       void __iomem *reg_base;  /* ioremap'ed address to registers */
+       unsigned long irq_flags; /* for request_irq() */
+
+       u16 flags;              /* custom mode flags */
+       u8 ocr;                 /* output control register */
+       u8 cdr;                 /* clock divider register */
 };
 
 struct net_device *alloc_sja1000dev(int sizeof_priv);
 };
 
 struct net_device *alloc_sja1000dev(int sizeof_priv);
diff --git a/kernel/2.6/drivers/net/can/sja1000/sja1000_isa.c b/kernel/2.6/drivers/net/can/sja1000/sja1000_isa.c
new file mode 100644 (file)
index 0000000..9d23cab
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#include <linux/io.h>
+#else
+#include <asm/io.h>
+#endif
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/platform/sja1000.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME "sja1000_isa"
+
+#define MAXDEV 8
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#error This driver does not support Kernel versions < 2.6.16
+#endif
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the ISA bus");
+MODULE_LICENSE("GPL v2");
+
+#define CLK_DEFAULT    16000000        /* 16 MHz */
+#define CDR_DEFAULT    (CDR_CBP | CDR_CLK_OFF)
+#define OCR_DEFAULT    OCR_TX0_PUSHPULL
+
+static unsigned long port[MAXDEV];
+static unsigned long mem[MAXDEV];
+static int __devinitdata irq[MAXDEV];
+static int __devinitdata clk[MAXDEV];
+static char __devinitdata cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static char __devinitdata ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+static char __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
+
+module_param_array(port, ulong, NULL, S_IRUGO);
+MODULE_PARM_DESC(port, "I/O port number");
+
+module_param_array(mem, ulong, NULL, S_IRUGO);
+MODULE_PARM_DESC(mem, "I/O memory address");
+
+module_param_array(indirect, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
+
+module_param_array(irq, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(irq, "IRQ number");
+
+module_param_array(clk, int, NULL, S_IRUGO);
+MODULE_PARM_DESC(clk, "External oscillator clock frequency "
+                "(default=16000000 [16 MHz])");
+
+module_param_array(cdr, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(cdr, "Clock divider register "
+                "(default=0x48 [CDR_CBP | CDR_CLK_OFF])");
+
+module_param_array(ocr, byte, NULL, S_IRUGO);
+MODULE_PARM_DESC(ocr, "Output control register "
+                "(default=0x18 [OCR_TX0_PUSHPULL])");
+
+#define SJA1000_IOSIZE          0x20
+#define SJA1000_IOSIZE_INDIRECT 0x02
+
+static u8 sja1000_isa_mem_read_reg(const struct sja1000_priv *priv, int reg)
+{
+       return readb(priv->reg_base + reg);
+}
+
+static void sja1000_isa_mem_write_reg(const struct sja1000_priv *priv,
+                                     int reg, u8 val)
+{
+       writeb(val, priv->reg_base + reg);
+}
+
+static u8 sja1000_isa_port_read_reg(const struct sja1000_priv *priv, int reg)
+{
+       return inb((unsigned long)priv->reg_base + reg);
+}
+
+static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
+                                      int reg, u8 val)
+{
+       outb(val, (unsigned long)priv->reg_base + reg);
+}
+
+static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
+                                            int reg)
+{
+       unsigned long base = (unsigned long)priv->reg_base;
+
+       outb(reg, base);
+       return inb(base + 1);
+}
+
+static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
+                                               int reg, u8 val)
+{
+       unsigned long base = (unsigned long)priv->reg_base;
+
+       outb(reg, base);
+       outb(val, base + 1);
+}
+
+static int __devinit sja1000_isa_match(struct device *pdev, unsigned int idx)
+{
+       if (port[idx] || mem[idx]) {
+               if (irq[idx])
+                       return 1;
+       } else if (idx)
+               return 0;
+
+       dev_err(pdev, "insufficient parameters supplied\n");
+       return 0;
+}
+
+static int __devinit sja1000_isa_probe(struct device *pdev, unsigned int idx)
+{
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       void __iomem *base = NULL;
+       int iosize = SJA1000_IOSIZE;
+       int err;
+
+       if (mem[idx]) {
+               if (!request_mem_region(mem[idx], iosize, DRV_NAME)) {
+                       err = -EBUSY;
+                       goto exit;
+               }
+               base = ioremap_nocache(mem[idx], iosize);
+               if (!base) {
+                       err = -ENOMEM;
+                       goto exit_release;
+               }
+       } else {
+               if (indirect[idx] > 0 ||
+                   (indirect[idx] == -1 && indirect[0] > 0))
+                       iosize = SJA1000_IOSIZE_INDIRECT;
+               if (!request_region(port[idx], iosize, DRV_NAME)) {
+                       err = -EBUSY;
+                       goto exit;
+               }
+       }
+
+       dev = alloc_sja1000dev(0);
+       if (!dev) {
+               err = -ENOMEM;
+               goto exit_unmap;
+       }
+       priv = netdev_priv(dev);
+
+       dev->irq = irq[idx];
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
+       if (mem[idx]) {
+               priv->reg_base = base;
+               dev->base_addr = mem[idx];
+               priv->read_reg = sja1000_isa_mem_read_reg;
+               priv->write_reg = sja1000_isa_mem_write_reg;
+       } else {
+               priv->reg_base = (void __iomem *)port[idx];
+               dev->base_addr = port[idx];
+
+               if (iosize == SJA1000_IOSIZE_INDIRECT) {
+                       priv->read_reg = sja1000_isa_port_read_reg_indirect;
+                       priv->write_reg = sja1000_isa_port_write_reg_indirect;
+               } else {
+                       priv->read_reg = sja1000_isa_port_read_reg;
+                       priv->write_reg = sja1000_isa_port_write_reg;
+               }
+       }
+
+       if (clk[idx])
+               priv->can.clock.freq = clk[idx] / 2;
+       else if (clk[0])
+               priv->can.clock.freq = clk[0] / 2;
+       else
+               priv->can.clock.freq = CLK_DEFAULT / 2;
+
+       if (ocr[idx] != -1)
+               priv->ocr = ocr[idx] & 0xff;
+       else if (ocr[0] != -1)
+               priv->ocr = ocr[0] & 0xff;
+       else
+               priv->ocr = OCR_DEFAULT;
+
+       if (cdr[idx] != -1)
+               priv->cdr = cdr[idx] & 0xff;
+       else if (cdr[0] != -1)
+               priv->cdr = cdr[0] & 0xff;
+       else
+               priv->cdr = CDR_DEFAULT;
+
+       dev_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, pdev);
+
+       err = register_sja1000dev(dev);
+       if (err) {
+               dev_err(pdev, "registering %s failed (err=%d)\n",
+                       DRV_NAME, err);
+               goto exit_unmap;
+       }
+
+       dev_info(pdev, "%s device registered (reg_base=0x%p, irq=%d)\n",
+                DRV_NAME, priv->reg_base, dev->irq);
+       return 0;
+
+ exit_unmap:
+       if (mem[idx])
+               iounmap(base);
+ exit_release:
+       if (mem[idx])
+               release_mem_region(mem[idx], iosize);
+       else
+               release_region(port[idx], iosize);
+ exit:
+       return err;
+}
+
+static int __devexit sja1000_isa_remove(struct device *pdev, unsigned int idx)
+{
+       struct net_device *dev = dev_get_drvdata(pdev);
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       unregister_sja1000dev(dev);
+       dev_set_drvdata(pdev, NULL);
+
+       if (mem[idx]) {
+               iounmap(priv->reg_base);
+               release_mem_region(mem[idx], SJA1000_IOSIZE);
+       } else {
+               if (priv->read_reg == sja1000_isa_port_read_reg_indirect)
+                       release_region(port[idx], SJA1000_IOSIZE_INDIRECT);
+               else
+                       release_region(port[idx], SJA1000_IOSIZE);
+       }
+       free_sja1000dev(dev);
+
+       return 0;
+}
+
+static struct isa_driver sja1000_isa_driver = {
+       .match = sja1000_isa_match,
+       .probe = sja1000_isa_probe,
+       .remove = __devexit_p(sja1000_isa_remove),
+       .driver = {
+               .name = DRV_NAME,
+       },
+};
+
+static int __init sja1000_isa_init(void)
+{
+       int err = isa_register_driver(&sja1000_isa_driver, MAXDEV);
+
+       if (!err)
+               printk(KERN_INFO
+                      "Legacy %s driver for max. %d devices registered\n",
+                      DRV_NAME, MAXDEV);
+       return err;
+}
+
+static void __exit sja1000_isa_exit(void)
+{
+       isa_unregister_driver(&sja1000_isa_driver);
+}
+
+module_init(sja1000_isa_init);
+module_exit(sja1000_isa_exit);
index f6c0cc46b91a03a807f76eefc43661e1a93000fe..6d608528f6b977d9176528ad1f776447713322c2 100644 (file)
  * definition in your flattened device tree source (DTS) file similar to:
  *
  *   can@3,100 {
  * definition in your flattened device tree source (DTS) file similar to:
  *
  *   can@3,100 {
- *           compatible = "philips,sja1000";
+ *           compatible = "nxp,sja1000";
  *           reg = <3 0x100 0x80>;
  *           reg = <3 0x100 0x80>;
- *           clock-frequency = <8000000>;
- *           cdr-reg = <0x48>;
- *           ocr-reg = <0x0a>;
  *           interrupts = <2 0>;
  *           interrupt-parent = <&mpic>;
  *           interrupts = <2 0>;
  *           interrupt-parent = <&mpic>;
+ *           nxp,external-clock-frequency = <16000000>;
  *   };
  *   };
+ *
+ * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further
+ * information.
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 
 #include <linux/of_platform.h>
 #include <asm/prom.h>
 
 #include <linux/of_platform.h>
 #include <asm/prom.h>
@@ -56,19 +58,21 @@ MODULE_LICENSE("GPL v2");
 #define SJA1000_OFP_OCR        OCR_TX0_PULLDOWN
 #define SJA1000_OFP_CDR        (CDR_CBP | CDR_CLK_OFF)
 
 #define SJA1000_OFP_OCR        OCR_TX0_PULLDOWN
 #define SJA1000_OFP_CDR        (CDR_CBP | CDR_CLK_OFF)
 
-static u8 sja1000_ofp_read_reg(struct net_device *dev, int reg)
+static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
 {
 {
-       return in_8((void __iomem *)(dev->base_addr + reg));
+       return in_8(priv->reg_base + reg);
 }
 
 }
 
-static void sja1000_ofp_write_reg(struct net_device *dev, int reg, u8 val)
+static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
+                                 int reg, u8 val)
 {
 {
-       out_8((void __iomem *)(dev->base_addr + reg), val);
+       out_8(priv->reg_base + reg, val);
 }
 
 static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
 {
        struct net_device *dev = dev_get_drvdata(&ofdev->dev);
 }
 
 static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
 {
        struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+       struct sja1000_priv *priv = netdev_priv(dev);
        struct device_node *np = ofdev->node;
        struct resource res;
 
        struct device_node *np = ofdev->node;
        struct resource res;
 
@@ -76,11 +80,11 @@ static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
 
        unregister_sja1000dev(dev);
        free_sja1000dev(dev);
 
        unregister_sja1000dev(dev);
        free_sja1000dev(dev);
-       iounmap((void __iomem *)dev->base_addr);
+       iounmap(priv->reg_base);
        irq_dispose_mapping(dev->irq);
 
        of_address_to_resource(np, 0, &res);
        irq_dispose_mapping(dev->irq);
 
        of_address_to_resource(np, 0, &res);
-       release_mem_region(res.start, res.end - res.start + 1);
+       release_mem_region(res.start, resource_size(&res));
 
        return 0;
 }
 
        return 0;
 }
@@ -102,18 +106,20 @@ static int __devinit sja1000_ofp_probe(struct of_device *ofdev,
                return err;
        }
 
                return err;
        }
 
-       res_size = res.end - res.start + 1;
+       res_size = resource_size(&res);
 
        if (!request_mem_region(res.start, res_size, DRV_NAME)) {
 
        if (!request_mem_region(res.start, res_size, DRV_NAME)) {
-               dev_err(&ofdev->dev, "couldn't request %#x..%#x\n",
-                       res.start, res.end);
+               dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n",
+                       (unsigned long long)res.start,
+                       (unsigned long long)res.end);
                return -EBUSY;
        }
 
        base = ioremap_nocache(res.start, res_size);
        if (!base) {
                return -EBUSY;
        }
 
        base = ioremap_nocache(res.start, res_size);
        if (!base) {
-               dev_err(&ofdev->dev, "couldn't ioremap %#x..%#x\n",
-                       res.start, res.end);
+               dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n",
+                       (unsigned long long)res.start,
+                       (unsigned long long)res.end);
                err = -ENOMEM;
                goto exit_release_mem;
        }
                err = -ENOMEM;
                goto exit_release_mem;
        }
@@ -136,30 +142,71 @@ static int __devinit sja1000_ofp_probe(struct of_device *ofdev,
        priv->read_reg = sja1000_ofp_read_reg;
        priv->write_reg = sja1000_ofp_write_reg;
 
        priv->read_reg = sja1000_ofp_read_reg;
        priv->write_reg = sja1000_ofp_write_reg;
 
+       /* backward compatibility */
        prop = of_get_property(np, "clock-frequency", &prop_size);
        prop = of_get_property(np, "clock-frequency", &prop_size);
+       if (!prop)
+               prop = of_get_property(np, "nxp,external-clock-frequency",
+                                      &prop_size);
+
        if (prop && (prop_size ==  sizeof(u32)))
        if (prop && (prop_size ==  sizeof(u32)))
-               priv->can.bittiming.clock = *prop;
+               priv->can.clock.freq = *prop / 2;
        else
        else
-               priv->can.bittiming.clock = SJA1000_OFP_CAN_CLOCK;
+               priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
 
 
+       /* backward compatibility */
        prop = of_get_property(np, "ocr-reg", &prop_size);
        prop = of_get_property(np, "ocr-reg", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
+       if (prop && (prop_size == sizeof(u32))) {
                priv->ocr = (u8)*prop;
                priv->ocr = (u8)*prop;
-       else
-               priv->ocr = SJA1000_OFP_OCR;
+       } else {
+
+               prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
+               if (prop && (prop_size == sizeof(u32)))
+                       priv->ocr |= *prop & OCR_MODE_MASK;
+               else
+                       priv->ocr |= OCR_MODE_NORMAL; /* default */
+
+               prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
+               if (prop && (prop_size == sizeof(u32)))
+                       priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+               else
+                       priv->ocr |= OCR_TX0_PULLDOWN; /* default */
+       }
 
 
+       /* backward compatibility */
        prop = of_get_property(np, "cdr-reg", &prop_size);
        prop = of_get_property(np, "cdr-reg", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
+       if (prop && (prop_size == sizeof(u32))) {
                priv->cdr = (u8)*prop;
                priv->cdr = (u8)*prop;
-       else
-               priv->cdr = SJA1000_OFP_CDR;
+       } else {
+               prop = of_get_property(np, "nxp,clock-out-frequency",
+                                      &prop_size);
+               if (prop && (prop_size == sizeof(u32)) && *prop) {
+                       u32 divider = priv->can.clock.freq * 2 / *prop;
+
+                       if (divider > 1)
+                               priv->cdr |= divider / 2 - 1;
+                       else
+                               priv->cdr |= CDR_CLKOUT_MASK;
+               } else {
+                       priv->cdr |= CDR_CLK_OFF; /* default */
+               }
+
+               prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
+               if (!prop)
+                       priv->cdr |= CDR_CBP; /* default */
+       }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+       priv->irq_flags = SA_SHIRQ;
+#else
+       priv->irq_flags = IRQF_SHARED;
+#endif
+       priv->reg_base = base;
 
 
-       dev->base_addr = (unsigned long)base;
        dev->irq = irq;
 
        dev_info(&ofdev->dev,
        dev->irq = irq;
 
        dev_info(&ofdev->dev,
-                "base=0x%lx irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
-                dev->base_addr, dev->irq, priv->can.bittiming.clock,
+                "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
+                priv->reg_base, dev->irq, priv->can.clock.freq,
                 priv->ocr, priv->cdr);
 
        dev_set_drvdata(&ofdev->dev, dev);
                 priv->ocr, priv->cdr);
 
        dev_set_drvdata(&ofdev->dev, dev);
index a6c5d760895f231daa5650960d40e0ea0b6ff1b4..d1bfaecd6a7818e690b48663b951bdf109d02834 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/kernel.h>
  */
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/platform/sja1000.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/platform/sja1000.h>
 #include <linux/io.h>
 
 #include "sja1000.h"
 
 #define DRV_NAME "sja1000_platform"
 
 #include <linux/io.h>
 
 #include "sja1000.h"
 
 #define DRV_NAME "sja1000_platform"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+#error This driver does not support Kernel versions < 2.6.27
+#endif
+
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
 MODULE_LICENSE("GPL v2");
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
 MODULE_LICENSE("GPL v2");
 
-static u8 sp_read_reg(struct net_device *dev, int reg)
+static u8 sp_read_reg(const struct sja1000_priv *priv, int reg)
 {
 {
-       return ioread8((void __iomem *)(dev->base_addr + reg));
+       return ioread8(priv->reg_base + reg);
 }
 
 }
 
-static void sp_write_reg(struct net_device *dev, int reg, u8 val)
+static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val)
 {
 {
-       iowrite8(val, (void __iomem *)(dev->base_addr + reg));
+       iowrite8(val, priv->reg_base + reg);
 }
 
 static int sp_probe(struct platform_device *pdev)
 {
 }
 
 static int sp_probe(struct platform_device *pdev)
 {
-       int err, irq;
+       int err;
        void __iomem *addr;
        struct net_device *dev;
        struct sja1000_priv *priv;
        void __iomem *addr;
        struct net_device *dev;
        struct sja1000_priv *priv;
@@ -70,24 +75,18 @@ static int sp_probe(struct platform_device *pdev)
                goto exit;
        }
 
                goto exit;
        }
 
-       if (!request_mem_region(res_mem->start,
-                               res_mem->end - res_mem->start + 1,
+       if (!request_mem_region(res_mem->start, resource_size(res_mem),
                                DRV_NAME)) {
                err = -EBUSY;
                goto exit;
        }
 
                                DRV_NAME)) {
                err = -EBUSY;
                goto exit;
        }
 
-       addr = ioremap_nocache(res_mem->start,
-                              res_mem->end - res_mem->start + 1);
+       addr = ioremap_nocache(res_mem->start, resource_size(res_mem));
        if (!addr) {
                err = -ENOMEM;
                goto exit_release;
        }
 
        if (!addr) {
                err = -ENOMEM;
                goto exit_release;
        }
 
-       irq = res_irq->start;
-       if (res_irq->flags & IRQF_TRIGGER_MASK)
-               set_irq_type(irq, res_irq->flags & IRQF_TRIGGER_MASK);
-
        dev = alloc_sja1000dev(0);
        if (!dev) {
                err = -ENOMEM;
        dev = alloc_sja1000dev(0);
        if (!dev) {
                err = -ENOMEM;
@@ -95,15 +94,15 @@ static int sp_probe(struct platform_device *pdev)
        }
        priv = netdev_priv(dev);
 
        }
        priv = netdev_priv(dev);
 
+       dev->irq = res_irq->start;
+       priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+       priv->reg_base = addr;
        priv->read_reg = sp_read_reg;
        priv->write_reg = sp_write_reg;
        priv->read_reg = sp_read_reg;
        priv->write_reg = sp_write_reg;
-       priv->can.bittiming.clock = pdata->clock;
+       priv->can.clock.freq = pdata->clock;
        priv->ocr = pdata->ocr;
        priv->cdr = pdata->cdr;
 
        priv->ocr = pdata->ocr;
        priv->cdr = pdata->cdr;
 
-       dev->irq = irq;
-       dev->base_addr = (unsigned long)addr;
-
        dev_set_drvdata(&pdev->dev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        dev_set_drvdata(&pdev->dev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -114,8 +113,8 @@ static int sp_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
                goto exit_free;
        }
 
-       dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n",
-                DRV_NAME, dev->base_addr, dev->irq);
+       dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
+                DRV_NAME, priv->reg_base, dev->irq);
        return 0;
 
  exit_free:
        return 0;
 
  exit_free:
@@ -123,7 +122,7 @@ static int sp_probe(struct platform_device *pdev)
  exit_iounmap:
        iounmap(addr);
  exit_release:
  exit_iounmap:
        iounmap(addr);
  exit_release:
-       release_mem_region(res_mem->start, res_mem->end - res_mem->start + 1);
+       release_mem_region(res_mem->start, resource_size(res_mem));
  exit:
        return err;
 }
  exit:
        return err;
 }
@@ -131,15 +130,17 @@ static int sp_probe(struct platform_device *pdev)
 static int sp_remove(struct platform_device *pdev)
 {
        struct net_device *dev = dev_get_drvdata(&pdev->dev);
 static int sp_remove(struct platform_device *pdev)
 {
        struct net_device *dev = dev_get_drvdata(&pdev->dev);
+       struct sja1000_priv *priv = netdev_priv(dev);
        struct resource *res;
 
        unregister_sja1000dev(dev);
        dev_set_drvdata(&pdev->dev, NULL);
        struct resource *res;
 
        unregister_sja1000dev(dev);
        dev_set_drvdata(&pdev->dev, NULL);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res->end - res->start + 1);
 
 
-       if (dev->base_addr)
-               iounmap((void __iomem *)dev->base_addr);
+       if (priv->reg_base)
+               iounmap(priv->reg_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
 
        free_sja1000dev(dev);
 
 
        free_sja1000dev(dev);
 
index 1f6c67724cf6b0c60edcc6a9825b50955ab57a2c..b29a0deae648ee9545063f1c81bbb1f393afa72b 100644 (file)
@@ -73,9 +73,9 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 
 #include <linux/delay.h>
 #include <linux/init.h>
 
-#include <linux/can.h>
+#include <socketcan/can.h>
 
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 static __initdata const char banner[] =
 RCSID("$Id$");
 
 static __initdata const char banner[] =
@@ -528,16 +528,31 @@ static int slc_open(struct net_device *dev)
        return 0;
 }
 
        return 0;
 }
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops slc_netdev_ops = {
+       .ndo_open               = slc_open,
+       .ndo_stop               = slc_close,
+       .ndo_start_xmit         = slc_xmit,
+#ifdef SLC_CHECK_TRANSMIT
+       .ndo_tx_timeout         = slc_tx_timeout,
+#endif
+};
+#endif
+
 /* Netdevice register callback */
 static void slc_setup(struct net_device *dev)
 {
 /* Netdevice register callback */
 static void slc_setup(struct net_device *dev)
 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops = &slc_netdev_ops;
+#else
        dev->open               = slc_open;
        dev->open               = slc_open;
-       dev->destructor         = free_netdev;
        dev->stop               = slc_close;
        dev->stop               = slc_close;
+       dev->hard_start_xmit    = slc_xmit;
+#endif
+       dev->destructor         = free_netdev;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        dev->get_stats          = slc_get_stats;
 #endif
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        dev->get_stats          = slc_get_stats;
 #endif
-       dev->hard_start_xmit    = slc_xmit;
 
        dev->hard_header_len    = 0;
        dev->addr_len           = 0;
 
        dev->hard_header_len    = 0;
        dev->addr_len           = 0;
@@ -546,7 +561,9 @@ static void slc_setup(struct net_device *dev)
        dev->mtu                = sizeof(struct can_frame);
        dev->type               = ARPHRD_CAN;
 #ifdef SLC_CHECK_TRANSMIT
        dev->mtu                = sizeof(struct can_frame);
        dev->type               = ARPHRD_CAN;
 #ifdef SLC_CHECK_TRANSMIT
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
        dev->tx_timeout         = slc_tx_timeout;
        dev->tx_timeout         = slc_tx_timeout;
+#endif
        dev->watchdog_timeo     = 20*HZ;
 #endif
 
        dev->watchdog_timeo     = 20*HZ;
 #endif
 
index df3fceca7bd014694a7fbe9b4511b80ecaeeb188..d65a5e9878e1a3ab6e9dc94d35e6e7aa7928eb2f 100644 (file)
@@ -13,7 +13,7 @@ else
 
 -include $(TOPDIR)/Makefile.common
 
 
 -include $(TOPDIR)/Makefile.common
 
-softing-y := softing_main.o softing_fw.o
+softing-y := softing_main.o softing_fw.o softing_sysfs.o
 obj-$(CONFIG_CAN_SOFTING)        += softing.o
 obj-$(CONFIG_CAN_SOFTING_CS)     += softing_cs.o
 
 obj-$(CONFIG_CAN_SOFTING)        += softing.o
 obj-$(CONFIG_CAN_SOFTING_CS)     += softing_cs.o
 
index e43c7f11679991c65291d63f42e0755aa9e6cac6..20da9189e8cfd84de4a18db02af97f8c76d1ab3a 100644 (file)
@@ -6,8 +6,9 @@
 
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <linux/ktime.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 
 struct softing;
 struct sofing_desc;
 
 struct softing;
 struct sofing_desc;
@@ -64,10 +65,13 @@ struct softing {
        int nbus;
        struct softing_priv *bus[2];
        spinlock_t       spin; /* protect this structure & DPRAM access */
        int nbus;
        struct softing_priv *bus[2];
        spinlock_t       spin; /* protect this structure & DPRAM access */
+       ktime_t boot_time;
+       u32 sample_at_boot_time;
 
        struct {
                /* indication of firmware status */
                int up;
 
        struct {
                /* indication of firmware status */
                int up;
+               int failed; /* firmware has failed */
                /* protection of the 'up' variable */
                struct mutex lock;
        } fw;
                /* protection of the 'up' variable */
                struct mutex lock;
        } fw;
@@ -101,7 +105,7 @@ struct softing {
                unsigned short manf;
                unsigned short prod;
                u32  serial, fw, hw, lic;
                unsigned short manf;
                unsigned short prod;
                u32  serial, fw, hw, lic;
-               u16  chip [2];
+               u16  chip[2];
                u32  freq;
                const char *name;
        } id;
                u32  freq;
                const char *name;
        } id;
@@ -133,7 +137,7 @@ extern const struct softing_desc *
 
 extern int softing_default_output(struct softing *card
                        , struct softing_priv *priv);
 
 extern int softing_default_output(struct softing *card
                        , struct softing_priv *priv);
-extern u32 softing_time2usec(struct softing *card, u32 raw);
+extern ktime_t softing_raw2ktime(struct softing *card, u32 raw);
 
 extern int softing_fct_cmd(struct softing *card
                        , int cmd, int vector, const char *msg);
 
 extern int softing_fct_cmd(struct softing *card
                        , int cmd, int vector, const char *msg);
@@ -155,11 +159,20 @@ extern int softing_reset_chip(struct softing *card);
  */
 extern int softing_card_irq(struct softing *card, int enable);
 
  */
 extern int softing_card_irq(struct softing *card, int enable);
 
-/* called when tx queue is flushed */
-extern void softing_flush_echo_skb(struct softing_priv *priv);
+/* start/stop 1 bus on cardr*/
+extern int softing_cycle(
+       struct softing *card, struct softing_priv *priv, int up);
 
 
-/* reinitaliase the card, apply -1 for bus[01] for 'no change' */
-extern int softing_reinit(struct softing *card, int bus0, int bus1);
+/* netif_rx() */
+extern int softing_rx(struct net_device *netdev, const struct can_frame *msg,
+       ktime_t ktime);
+
+/* create/remove the per-card associated sysfs entries */
+extern int softing_card_sysfs_create(struct softing *card);
+extern void softing_card_sysfs_remove(struct softing *card);
+/* create/remove the per-bus associated sysfs entries */
+extern int softing_bus_sysfs_create(struct softing_priv *bus);
+extern void softing_bus_sysfs_remove(struct softing_priv *bus);
 
 /* SOFTING DPRAM mappings */
 struct softing_rx {
 
 /* SOFTING DPRAM mappings */
 struct softing_rx {
@@ -244,25 +257,3 @@ struct softing_info {
 /* debug */
 extern int softing_debug;
 
 /* debug */
 extern int softing_debug;
 
-#define mod_alert(fmt,arg...) { \
-       if (softing_debug >= 0) \
-               printk(KERN_ALERT "[%s] %s:" fmt "\n" \
-                       , THIS_MODULE->name \
-                       , __func__ \
-                       , ##arg); \
-       }
-#define mod_info(fmt,arg...) { \
-       if (softing_debug >= 1) \
-               printk(KERN_INFO        "[%s] %s:" fmt "\n"\
-                       , THIS_MODULE->name \
-                       , __func__ \
-                       , ##arg); \
-       }
-#define mod_trace(fmt,arg...) { \
-       if (softing_debug >= 2) \
-               printk(KERN_DEBUG "[%s] %s:" fmt "\n" \
-                       , THIS_MODULE->name \
-                       , __func__ \
-                       , ##arg); \
-       }
-
index e33b614de28f0a63f09e401ddb53f5b1f5fee8a4..7923744c6af597038ddc6a1d60df02bed18fc6dd 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -103,7 +104,7 @@ static int card_enable_irq_via_pcmcia(struct softing *sdev, int v)
        reg.Value        = v ? 0x60 : 0;
        ret = pcmcia_access_configuration_register(pcmcia, &reg);
        if (ret)
        reg.Value        = v ? 0x60 : 0;
        ret = pcmcia_access_configuration_register(pcmcia, &reg);
        if (ret)
-               mod_alert("failed %u", ret);
+               dev_alert(&pcmcia->dev, "failed %u\n", ret);
        return ret;
 }
 
        return ret;
 }
 
@@ -209,12 +210,12 @@ static int dev_conf_check(struct pcmcia_device *pdev,
        /* power settings (Vcc & Vpp) */
        if (cf->vcc.present & (1 << CISTPL_POWER_VNOM)) {
                if (vcc != cf->vcc.param[CISTPL_POWER_VNOM]/10000) {
        /* power settings (Vcc & Vpp) */
        if (cf->vcc.present & (1 << CISTPL_POWER_VNOM)) {
                if (vcc != cf->vcc.param[CISTPL_POWER_VNOM]/10000) {
-                       mod_alert("%s: cf->Vcc mismatch\n", __FILE__);
+                       dev_alert(&pdev->dev, "cf->Vcc mismatch\n");
                        goto do_next;
                }
        } else if (def_cf->vcc.present & (1 << CISTPL_POWER_VNOM)) {
                if (vcc != def_cf->vcc.param[CISTPL_POWER_VNOM]/10000) {
                        goto do_next;
                }
        } else if (def_cf->vcc.present & (1 << CISTPL_POWER_VNOM)) {
                if (vcc != def_cf->vcc.param[CISTPL_POWER_VNOM]/10000) {
-                       mod_alert("%s: cf->Vcc mismatch\n", __FILE__);
+                       dev_alert(&pdev->dev, "cf->Vcc mismatch\n");
                        goto do_next;
                }
        }
                        goto do_next;
                }
        }
@@ -249,7 +250,8 @@ static int dev_conf_check(struct pcmcia_device *pdev,
                csdev->win.AccessSpeed = 0;
                ret = pcmcia_request_window(&pdev, &csdev->win, &pdev->win);
                if (ret) {
                csdev->win.AccessSpeed = 0;
                ret = pcmcia_request_window(&pdev, &csdev->win, &pdev->win);
                if (ret) {
-                       mod_alert("pcmcia_request_window() mismatch\n");
+                       dev_alert(&pdev->dev,
+                               "pcmcia_request_window() mismatch\n");
                        goto do_next;
                }
                /* softing specific: choose slower access for old cards */
                        goto do_next;
                }
                /* softing specific: choose slower access for old cards */
@@ -261,11 +263,13 @@ static int dev_conf_check(struct pcmcia_device *pdev,
                map.Page = 0;
                map.CardOffset = mem->win[0].card_addr;
                if (pcmcia_map_mem_page(pdev->win, &map)) {
                map.Page = 0;
                map.CardOffset = mem->win[0].card_addr;
                if (pcmcia_map_mem_page(pdev->win, &map)) {
-                       mod_alert("pcmcia_map_mem_page() mismatch\n");
+                       dev_alert(&pdev->dev,
+                               "pcmcia_map_mem_page() mismatch\n");
                        goto do_next_win;
                }
        } else {
                        goto do_next_win;
                }
        } else {
-               mod_info("no memory window in tuple %u", cf->index);
+               dev_info(&pdev->dev, "no memory window in tuple %u\n",
+                       cf->index);
                goto do_next;
        }
        return 0;
                goto do_next;
        }
        return 0;
@@ -279,7 +283,8 @@ static void driver_remove(struct pcmcia_device *pcmcia)
 {
        struct softing *card = (struct softing *)pcmcia->priv;
        struct softing_cs *cs = softing2cs(card);
 {
        struct softing *card = (struct softing *)pcmcia->priv;
        struct softing_cs *cs = softing2cs(card);
-       mod_trace("%s,device'%s'", card->id.name, pcmcia->devname);
+       dev_dbg(&pcmcia->dev, "%s, device '%s'\n"
+               , card->id.name, pcmcia->devname);
        rm_softing(card);
        /* release pcmcia stuff */
        pcmcia_disable_device(pcmcia);
        rm_softing(card);
        /* release pcmcia stuff */
        pcmcia_disable_device(pcmcia);
@@ -290,9 +295,11 @@ static void driver_remove(struct pcmcia_device *pcmcia)
 static int __devinit driver_probe(struct pcmcia_device *pcmcia)
 {
        struct softing_cs *cs;
 static int __devinit driver_probe(struct pcmcia_device *pcmcia)
 {
        struct softing_cs *cs;
-       struct softing          *card;
+       struct softing *card;
+       char *str;
+       char line[1024]; /* possible memory corruption */
 
 
-       mod_trace("on %s", pcmcia->devname);
+       dev_dbg(&pcmcia->dev, "on %s\n", pcmcia->devname);
 
        /* Create new softing device */
        cs = kzalloc(sizeof(*cs), GFP_KERNEL);
 
        /* Create new softing device */
        cs = kzalloc(sizeof(*cs), GFP_KERNEL);
@@ -334,35 +341,37 @@ static int __devinit driver_probe(struct pcmcia_device *pcmcia)
        card->dpram.size = cs->win.Size;
 
        if (card->dpram.size != 0x1000) {
        card->dpram.size = cs->win.Size;
 
        if (card->dpram.size != 0x1000) {
-               mod_alert("dpram size 0x%lx mismatch\n", card->dpram.size);
+               dev_alert(&pcmcia->dev, "dpram size 0x%lx mismatch\n",
+                       card->dpram.size);
                goto wrong_dpram;
        }
 
        /* Finally, report what we've done */
                goto wrong_dpram;
        }
 
        /* Finally, report what we've done */
-       printk(KERN_INFO "[%s] %s: index 0x%02x",
-                       THIS_MODULE->name,
-                       pcmcia->devname,
-                       pcmcia->conf.ConfigIndex);
+       str = line;
+       str += sprintf(str, "config index %u", pcmcia->conf.ConfigIndex);
        if (pcmcia->conf.Vpp)
        if (pcmcia->conf.Vpp)
-               printk(", Vpp %d.%d", pcmcia->conf.Vpp/10, pcmcia->conf.Vpp%10);
+               str += sprintf(str, ", Vpp %d.%d",
+                       pcmcia->conf.Vpp/10, pcmcia->conf.Vpp%10);
        if (pcmcia->conf.Attributes & CONF_ENABLE_IRQ) {
        if (pcmcia->conf.Attributes & CONF_ENABLE_IRQ) {
-               printk(", irq %d", pcmcia->irq.AssignedIRQ);
+               str += sprintf(str, ", irq %d", pcmcia->irq.AssignedIRQ);
                card->irq.nr = pcmcia->irq.AssignedIRQ;
        }
                card->irq.nr = pcmcia->irq.AssignedIRQ;
        }
+
        if (pcmcia->win) {
                int tmp;
                const char *p;
        if (pcmcia->win) {
                int tmp;
                const char *p;
-               printk(", mem 0x%08lx-0x%08lx"
+               str += sprintf(str, ", mem 0x%08lx-0x%08lx"
                        , card->dpram.phys
                        , card->dpram.phys + card->dpram.size-1);
                tmp = cs->win.Attributes;
                while (tmp) {
                        p = lookup_mask(pcmcia_mem_attr, &tmp);
                        , card->dpram.phys
                        , card->dpram.phys + card->dpram.size-1);
                tmp = cs->win.Attributes;
                while (tmp) {
                        p = lookup_mask(pcmcia_mem_attr, &tmp);
-                       if (p)
-                               printk(" %s", p);
+                       if (!p)
+                               continue;
+                       str += sprintf(str, " %s", p);
                }
        }
                }
        }
-       printk("\n");
+       dev_info(&pcmcia->dev, "%s\n", line);
 
        if (mk_softing(card))
                goto softing_failed;
 
        if (mk_softing(card))
                goto softing_failed;
@@ -407,13 +416,11 @@ static struct pcmcia_driver softing_cs_driver = {
 
 static int __init mod_start(void)
 {
 
 static int __init mod_start(void)
 {
-       mod_trace("");
        return pcmcia_register_driver(&softing_cs_driver);
 }
 
 static void __exit mod_stop(void)
 {
        return pcmcia_register_driver(&softing_cs_driver);
 }
 
 static void __exit mod_stop(void)
 {
-       mod_trace("");
        pcmcia_unregister_driver(&softing_cs_driver);
 }
 
        pcmcia_unregister_driver(&softing_cs_driver);
 }
 
index 4d20774c9cb9ed59dea8fb60a37097459490dd7c..ae913add6fefad77dfbc4d2a190330ccfa333f89 100644 (file)
@@ -171,7 +171,8 @@ int softing_fct_cmd(struct softing *card, int cmd, int vector, const char *msg)
                        /*don't read return-value now */
                        ret = card->dpram.fct->returned;
                        if (ret)
                        /*don't read return-value now */
                        ret = card->dpram.fct->returned;
                        if (ret)
-                               mod_alert("%s returned %u", msg, ret);
+                               dev_alert(card->dev,
+                                       "%s returned %u\n", msg, ret);
                        return 0;
                }
                if ((jiffies - stamp) >= 1 * HZ)
                        return 0;
                }
                if ((jiffies - stamp) >= 1 * HZ)
@@ -184,12 +185,14 @@ int softing_fct_cmd(struct softing *card, int cmd, int vector, const char *msg)
        } while (!signal_pending(current));
 
        if (ret == RES_NONE) {
        } while (!signal_pending(current));
 
        if (ret == RES_NONE) {
-               mod_alert("%s, no response from card on %u/0x%02x"
-                       , msg, cmd, vector);
+               dev_alert(card->dev,
+                       "%s, no response from card on %u/0x%02x\n",
+                       msg, cmd, vector);
                return 1;
        } else {
                return 1;
        } else {
-               mod_alert("%s, bad response from card on %u/0x%02x, 0x%04x"
-                       , msg, cmd, vector, ret);
+               dev_alert(card->dev,
+                       "%s, bad response from card on %u/0x%02x, 0x%04x\n",
+                       msg, cmd, vector, ret);
                /*make sure to return something not 0 */
                return ret ? ret : 1;
        }
                /*make sure to return something not 0 */
                return ret ? ret : 1;
        }
@@ -219,16 +222,18 @@ int softing_bootloader_command(struct softing *card
 
        switch (ret) {
        case RES_NONE:
 
        switch (ret) {
        case RES_NONE:
-               mod_alert("%s: no response from card", msg);
+               dev_alert(card->dev, "%s: no response from card\n", msg);
                break;
        case RES_NOK:
                break;
        case RES_NOK:
-               mod_alert("%s: response from card nok", msg);
+               dev_alert(card->dev, "%s: response from card nok\n", msg);
                break;
        case RES_UNKNOWN:
                break;
        case RES_UNKNOWN:
-               mod_alert("%s: command 0x%04x unknown", msg, command);
+               dev_alert(card->dev, "%s: command 0x%04x unknown\n",
+                       msg, command);
                break;
        default:
                break;
        default:
-               mod_alert("%s: bad response from card (%u)]", msg, ret);
+               dev_alert(card->dev, "%s: bad response from card (%u)]\n",
+                       msg, ret);
                break;
        }
        return ret ? ret : 1;
                break;
        }
        return ret ? ret : 1;
@@ -273,16 +278,18 @@ int softing_load_fw(const char *file, struct softing *card,
        u32 start_addr;
        struct fw_hdr rec;
        int ok = 0;
        u32 start_addr;
        struct fw_hdr rec;
        int ok = 0;
-       unsigned char buf[256];
+       unsigned char buf[1024];
 
        ret = request_firmware(&fw, file, card->dev);
        if (ret) {
 
        ret = request_firmware(&fw, file, card->dev);
        if (ret) {
-               mod_alert("request_firmware(%s) got %i", file, ret);
+               dev_alert(card->dev, "request_firmware(%s) got %i\n",
+                       file, ret);
                return ret;
        }
                return ret;
        }
-       mod_trace("%s, firmware(%s) got %u bytes, offset %c0x%04x"
-                       , card->id.name, file, (unsigned int)fw->size,
-                 (offset >= 0) ? '+' : '-', abs(offset));
+       dev_dbg(card->dev, "%s, firmware(%s) got %u bytes"
+               ", offset %c0x%04x\n",
+               card->id.name, file, (unsigned int)fw->size,
+               (offset >= 0) ? '+' : '-', abs(offset));
        /* parse the firmware */
        mem = fw->data;
        end = &mem[fw->size];
        /* parse the firmware */
        mem = fw->data;
        end = &mem[fw->size];
@@ -290,12 +297,14 @@ int softing_load_fw(const char *file, struct softing *card,
        if (fw_parse(&mem, &rec))
                goto fw_end;
        if (rec.type != 0xffff) {
        if (fw_parse(&mem, &rec))
                goto fw_end;
        if (rec.type != 0xffff) {
-               mod_alert("firware starts with type 0x%04x", rec.type);
+               dev_alert(card->dev, "firware starts with type 0x%04x\n",
+                       rec.type);
                goto fw_end;
        }
        if (strncmp("Structured Binary Format, Softing GmbH"
                        , rec.base, rec.len)) {
                goto fw_end;
        }
        if (strncmp("Structured Binary Format, Softing GmbH"
                        , rec.base, rec.len)) {
-               mod_info("firware string '%.*s'", rec.len, rec.base);
+               dev_info(card->dev, "firware string '%.*s'\n",
+                       rec.len, rec.base);
                goto fw_end;
        }
        ok |= 1;
                goto fw_end;
        }
        ok |= 1;
@@ -313,13 +322,15 @@ int softing_load_fw(const char *file, struct softing *card,
                        ok |= 4;
                        goto fw_end;
                } else if (rec.type != 0) {
                        ok |= 4;
                        goto fw_end;
                } else if (rec.type != 0) {
-                       mod_alert("unknown record type 0x%04x", rec.type);
+                       dev_alert(card->dev, "unknown record type 0x%04x\n",
+                               rec.type);
                        break;
                }
 
                if ((rec.addr + rec.len + offset) > size) {
                        break;
                }
 
                if ((rec.addr + rec.len + offset) > size) {
-                       mod_alert("firmware out of range (0x%08x / 0x%08x)"
-                       , (rec.addr + rec.len + offset), size);
+                       dev_alert(card->dev,
+                               "firmware out of range (0x%08x / 0x%08x)\n",
+                               (rec.addr + rec.len + offset), size);
                        goto fw_end;
                }
                memcpy_toio(&virt[rec.addr + offset],
                        goto fw_end;
                }
                memcpy_toio(&virt[rec.addr + offset],
@@ -327,8 +338,9 @@ int softing_load_fw(const char *file, struct softing *card,
                /* be sure to flush caches from IO space */
                mb();
                if (rec.len > sizeof(buf)) {
                /* be sure to flush caches from IO space */
                mb();
                if (rec.len > sizeof(buf)) {
-                       mod_info("record is big (%u bytes), not verifying"
-                               , rec.len);
+                       dev_info(card->dev,
+                               "record is big (%u bytes), not verifying\n",
+                               rec.len);
                        continue;
                }
                /* verify record data */
                        continue;
                }
                /* verify record data */
@@ -336,8 +348,8 @@ int softing_load_fw(const char *file, struct softing *card,
                if (!memcmp(buf, rec.base, rec.len))
                        /* is ok */
                        continue;
                if (!memcmp(buf, rec.base, rec.len))
                        /* is ok */
                        continue;
-               mod_alert("0x%08x:0x%03x at 0x%p failed", rec.addr, rec.len
-                       , &virt[rec.addr + offset]);
+               dev_alert(card->dev, "0x%08x:0x%03x at 0x%p failed\n",
+                       rec.addr, rec.len, &virt[rec.addr + offset]);
                goto fw_end;
        }
 fw_end:
                goto fw_end;
        }
 fw_end:
@@ -346,7 +358,7 @@ fw_end:
                /*got eof & start */
                return 0;
        }
                /*got eof & start */
                return 0;
        }
-       mod_alert("failed");
+       dev_info(card->dev, "firmware %s failed\n", file);
        return EINVAL;
 }
 
        return EINVAL;
 }
 
@@ -370,14 +382,20 @@ int softing_load_app_fw(const char *file, struct softing *card)
                u8 do_cs;
        } __attribute__((packed)) *pcpy =
                 (struct cpy *)&card->dpram.command[1];
                u8 do_cs;
        } __attribute__((packed)) *pcpy =
                 (struct cpy *)&card->dpram.command[1];
+       struct cmd {
+               u32 start;
+               u8 autorestart;
+       } __attribute__((packed)) *pcmdstart =
+               (struct cmd *)&card->dpram.command[1];
 
        ret = request_firmware(&fw, file, card->dev);
        if (ret) {
 
        ret = request_firmware(&fw, file, card->dev);
        if (ret) {
-               mod_alert("request_firmware(%s) got %i", file, ret);
+               dev_alert(card->dev, "request_firmware(%s) got %i\n",
+                       file, ret);
                return ret;
        }
                return ret;
        }
-       mod_trace("%s, firmware(%s) got %lu bytes", card->id.name, file,
-                 (unsigned long)fw->size);
+       dev_dbg(card->dev, "%s, firmware(%s) got %lu bytes\n",
+               card->id.name, file, (unsigned long)fw->size);
        /* parse the firmware */
        mem = fw->data;
        end = &mem[fw->size];
        /* parse the firmware */
        mem = fw->data;
        end = &mem[fw->size];
@@ -385,12 +403,14 @@ int softing_load_app_fw(const char *file, struct softing *card)
        if (fw_parse(&mem, &rec))
                goto fw_end;
        if (rec.type != 0xffff) {
        if (fw_parse(&mem, &rec))
                goto fw_end;
        if (rec.type != 0xffff) {
-               mod_alert("firware starts with type 0x%04x", rec.type);
+               dev_alert(card->dev, "firware starts with type 0x%04x\n",
+                       rec.type);
                goto fw_end;
        }
        if (strncmp("Structured Binary Format, Softing GmbH"
                , rec.base, rec.len)) {
                goto fw_end;
        }
        if (strncmp("Structured Binary Format, Softing GmbH"
                , rec.base, rec.len)) {
-               mod_info("firware string '%.*s'", rec.len, rec.base);
+               dev_alert(card->dev, "firware string '%.*s' fault\n",
+                       rec.len, rec.base);
                goto fw_end;
        }
        ok |= 1;
                goto fw_end;
        }
        ok |= 1;
@@ -409,7 +429,8 @@ int softing_load_app_fw(const char *file, struct softing *card)
                        ok |= 4;
                        goto fw_end;
                } else if (rec.type != 0) {
                        ok |= 4;
                        goto fw_end;
                } else if (rec.type != 0) {
-                       mod_alert("unknown record type 0x%04x", rec.type);
+                       dev_alert(card->dev, "unknown record type 0x%04x\n",
+                               rec.type);
                        break;
                }
                /* regualar data */
                        break;
                }
                /* regualar data */
@@ -428,34 +449,29 @@ int softing_load_app_fw(const char *file, struct softing *card)
                /*verify checksum */
                rx_sum = card->dpram.receipt[1];
                if (rx_sum != (sum & 0xffff)) {
                /*verify checksum */
                rx_sum = card->dpram.receipt[1];
                if (rx_sum != (sum & 0xffff)) {
-                       mod_alert("SRAM seems to be damaged"
-                               ", wanted 0x%04x, got 0x%04x", sum, rx_sum);
+                       dev_alert(card->dev, "SRAM seems to be damaged"
+                               ", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
                        goto fw_end;
                }
        }
 fw_end:
        release_firmware(fw);
                        goto fw_end;
                }
        }
 fw_end:
        release_firmware(fw);
-       if (ok == 7) {
-               /*got start, start_addr, & eof */
-               struct cmd {
-                       u32 start;
-                       u8 autorestart;
-               } *pcmd = (struct cmd *)&card->dpram.command[1];
-               pcmd->start = start_addr;
-               pcmd->autorestart = 1;
-               if (!softing_bootloader_command(card, 3, "start app.")) {
-                       mod_trace("%s: card app. run at 0x%06x"
-                               , card->id.name, start_addr);
-                       return 0;
-               }
-       }
-       mod_alert("failed");
+       if (ok != 7)
+               goto fw_failed;
+       /*got start, start_addr, & eof */
+       pcmdstart->start = start_addr;
+       pcmdstart->autorestart = 1;
+       if (softing_bootloader_command(card, 3, "start app."))
+               goto fw_failed;
+       dev_info(card->dev, "firmware %s up\n", file);
+       return 0;
+fw_failed:
+       dev_info(card->dev, "firmware %s failed\n", file);
        return EINVAL;
 }
 
 int softing_reset_chip(struct softing *card)
 {
        return EINVAL;
 }
 
 int softing_reset_chip(struct softing *card)
 {
-       mod_trace("%s", card->id.name);
        do {
                /*reset chip */
                card->dpram.info->reset_rcv_fifo = 0;
        do {
                /*reset chip */
                card->dpram.info->reset_rcv_fifo = 0;
@@ -476,58 +492,77 @@ failed:
        return -EIO;
 }
 
        return -EIO;
 }
 
-int softing_reinit(struct softing *card, int bus0, int bus1)
+int softing_cycle(struct softing *card, struct softing_priv *bus, int up)
 {
        int ret;
 {
        int ret;
-       int restarted_bus = -1;
-       mod_trace("%s", card->id.name);
+       struct softing_priv *pbus;
+       int mask_start;
+       int j;
+       struct can_frame msg;
+
        if (!card->fw.up)
                return -EIO;
        if (!card->fw.up)
                return -EIO;
-       if (bus0 < 0) {
-               bus0 = (card->bus[0]->netdev->flags & IFF_UP) ? 1 : 0;
-               if (bus0)
-                       restarted_bus = 0;
-       } else if (bus1 < 0) {
-               bus1 = (card->bus[1]->netdev->flags & IFF_UP) ? 1 : 0;
-               if (bus1)
-                       restarted_bus = 1;
-       }
-       /* collect info */
-       if (card->bus[0]) {
-               card->bus[0]->can.state = CAN_STATE_STOPPED;
-               softing_flush_echo_skb(card->bus[0]);
-       }
-       if (card->bus[1]) {
-               card->bus[1]->can.state = CAN_STATE_STOPPED;
-               softing_flush_echo_skb(card->bus[1]);
-       }
 
 
-       /* start acting */
-       if (!bus0 && !bus1) {
-               softing_card_irq(card, 0);
-               softing_reset_chip(card);
-               if (card->bus[0])
-                       netif_carrier_off(card->bus[0]->netdev);
-               if (card->bus[1])
-                       netif_carrier_off(card->bus[1]->netdev);
-               return 0;
-       }
-       ret = softing_reset_chip(card);
-       if (ret) {
-               softing_card_irq(card, 0);
+       ret = mutex_lock_interruptible(&card->fw.lock);
+       if (ret)
                return ret;
                return ret;
+       if (card->fw.failed)
+               goto failed_already;
+
+       mask_start = 0;
+       /* bring netdevs down */
+       for (j = 0; j < card->nbus; ++j) {
+               pbus = card->bus[j];
+               if (!pbus)
+                       continue;
+
+               if (bus != pbus)
+                       netif_stop_queue(pbus->netdev);
+
+               if ((bus != pbus) && netif_running(pbus->netdev))
+                       mask_start |= (1 << j);
+               if (netif_running(pbus->netdev)) {
+                       pbus->tx.pending = 0;
+                       pbus->tx.echo_put = 0;
+                       pbus->tx.echo_get = 0;
+                       /* this bus' may just have called open_candev()
+                        * which is rather stupid to call close_candev()
+                        * already
+                        * but we may come here from busoff recovery too
+                        * in which case the echo_skb _needs_ flushing too.
+                        * just be sure to call open_candev() again
+                        */
+                       close_candev(pbus->netdev);
+               }
+               pbus->can.state = CAN_STATE_STOPPED;
        }
        }
-       if (bus0) {
-               /*init chip */
-               card->dpram.fct->param[1] = card->bus[0]->can.bittiming.brp;
-               card->dpram.fct->param[2] = card->bus[0]->can.bittiming.sjw;
+       card->tx.pending = 0;
+       if (bus && up)
+               /* prepare to start this bus as well */
+               mask_start |= (1 << bus->index);
+
+       softing_card_irq(card, 0);
+       ret = softing_reset_chip(card);
+       if (ret)
+               goto failed;
+       if (!mask_start)
+               /* no busses to be brought up */
+               goto card_done;
+
+       /* from here, we must jump to failed: */
+
+       if (mask_start & 1) {
+               pbus = card->bus[0];
+               /*init chip 1 */
+               card->dpram.fct->param[1] = pbus->can.bittiming.brp;
+               card->dpram.fct->param[2] = pbus->can.bittiming.sjw;
                card->dpram.fct->param[3] =
                card->dpram.fct->param[3] =
-                        card->bus[0]->can.bittiming.phase_seg1 +
-                        card->bus[0]->can.bittiming.prop_seg;
+                       pbus->can.bittiming.phase_seg1 +
+                       pbus->can.bittiming.prop_seg;
                card->dpram.fct->param[4] =
                card->dpram.fct->param[4] =
-                        card->bus[0]->can.bittiming.phase_seg2;
-               card->dpram.fct->param[5] = (card->bus[0]->can.ctrlmode &
-                                            CAN_CTRLMODE_3_SAMPLES)?1:0;
+                       pbus->can.bittiming.phase_seg2;
+               card->dpram.fct->param[5] = (pbus->can.ctrlmode &
+                       CAN_CTRLMODE_3_SAMPLES) ? 1 : 0;
                if (softing_fct_cmd(card, 1, 0, "initialize_chip[0]"))
                        goto failed;
                /*set mode */
                if (softing_fct_cmd(card, 1, 0, "initialize_chip[0]"))
                        goto failed;
                /*set mode */
@@ -545,21 +580,22 @@ int softing_reinit(struct softing *card, int bus0, int bus1)
                if (softing_fct_cmd(card, 7, 0, "set_filter[0]"))
                        goto failed;
                /*set output control */
                if (softing_fct_cmd(card, 7, 0, "set_filter[0]"))
                        goto failed;
                /*set output control */
-               card->dpram.fct->param[1] = card->bus[0]->output;
+               card->dpram.fct->param[1] = pbus->output;
                if (softing_fct_cmd(card, 5, 0, "set_output[0]"))
                        goto failed;
        }
                if (softing_fct_cmd(card, 5, 0, "set_output[0]"))
                        goto failed;
        }
-       if (bus1) {
+       if (mask_start & 2) {
+               pbus = card->bus[1];
                /*init chip2 */
                /*init chip2 */
-               card->dpram.fct->param[1] = card->bus[1]->can.bittiming.brp;
-               card->dpram.fct->param[2] = card->bus[1]->can.bittiming.sjw;
+               card->dpram.fct->param[1] = pbus->can.bittiming.brp;
+               card->dpram.fct->param[2] = pbus->can.bittiming.sjw;
                card->dpram.fct->param[3] =
                card->dpram.fct->param[3] =
-                        card->bus[1]->can.bittiming.phase_seg1 +
-                        card->bus[1]->can.bittiming.prop_seg;
+                       pbus->can.bittiming.phase_seg1 +
+                       pbus->can.bittiming.prop_seg;
                card->dpram.fct->param[4] =
                card->dpram.fct->param[4] =
-                        card->bus[1]->can.bittiming.phase_seg2;
-               card->dpram.fct->param[5] = (card->bus[1]->can.ctrlmode &
-                                            CAN_CTRLMODE_3_SAMPLES)?1:0;
+                       pbus->can.bittiming.phase_seg2;
+               card->dpram.fct->param[5] = (pbus->can.ctrlmode &
+                       CAN_CTRLMODE_3_SAMPLES) ? 1 : 0;
                if (softing_fct_cmd(card, 2, 0, "initialize_chip[1]"))
                        goto failed;
                /*set mode2 */
                if (softing_fct_cmd(card, 2, 0, "initialize_chip[1]"))
                        goto failed;
                /*set mode2 */
@@ -577,14 +613,15 @@ int softing_reinit(struct softing *card, int bus0, int bus1)
                if (softing_fct_cmd(card, 8, 0, "set_filter[1]"))
                        goto failed;
                /*set output control2 */
                if (softing_fct_cmd(card, 8, 0, "set_filter[1]"))
                        goto failed;
                /*set output control2 */
-               card->dpram.fct->param[1] = card->bus[1]->output;
+               card->dpram.fct->param[1] = pbus->output;
                if (softing_fct_cmd(card, 6, 0, "set_output[1]"))
                        goto failed;
        }
                if (softing_fct_cmd(card, 6, 0, "set_output[1]"))
                        goto failed;
        }
-       /*set interrupt */
        /*enable_error_frame */
        /*enable_error_frame */
+       /*
        if (softing_fct_cmd(card, 51, 0, "enable_error_frame"))
                goto failed;
        if (softing_fct_cmd(card, 51, 0, "enable_error_frame"))
                goto failed;
+       */
        /*initialize interface */
        card->dpram.fct->param[1] = 1;
        card->dpram.fct->param[2] = 1;
        /*initialize interface */
        card->dpram.fct->param[1] = 1;
        card->dpram.fct->param[2] = 1;
@@ -614,39 +651,67 @@ int softing_reinit(struct softing *card, int bus0, int bus1)
                goto failed;
        card->dpram.info->bus_state = 0;
        card->dpram.info->bus_state2 = 0;
                goto failed;
        card->dpram.info->bus_state = 0;
        card->dpram.info->bus_state2 = 0;
-       mod_info("ok for %s, %s/%s\n", card->bus[0]->netdev->name,
-                card->bus[1]->netdev->name, card->id.name);
+       dev_info(card->dev, "ok for %s, %s/%s\n",
+               card->bus[0]->netdev->name, card->bus[1]->netdev->name,
+               card->id.name);
        if (card->desc->generation < 2) {
                card->dpram.irq->to_host = 0;
                /* flush the DPRAM caches */
                wmb();
        }
        if (card->desc->generation < 2) {
                card->dpram.irq->to_host = 0;
                /* flush the DPRAM caches */
                wmb();
        }
+
+       card->boot_time = ktime_get_real();
+
        /*run once */
        /*the bottom halve will start flushing the tx-queue too */
        /*run once */
        /*the bottom halve will start flushing the tx-queue too */
-       tasklet_schedule(&card->irq.bh);
-
+       /*tasklet_schedule(&card->irq.bh);*/
        ret = softing_card_irq(card, 1);
        if (ret)
                goto failed;
 
        ret = softing_card_irq(card, 1);
        if (ret)
                goto failed;
 
-       /*TODO: generate RESTARTED messages */
-
-       if (card->bus[0] && bus0) {
-               card->bus[0]->can.state = CAN_STATE_ACTIVE;
-               netif_carrier_on(card->bus[0]->netdev);
-       }
-       if (card->bus[1] && bus1) {
-               card->bus[1]->can.state = CAN_STATE_ACTIVE;
-               netif_carrier_on(card->bus[1]->netdev);
+       /*
+        * do socketcan notifications/status changes
+        * from here, no errors should occur, or the failed: part
+        * must be reviewed
+        */
+       memset(&msg, 0, sizeof(msg));
+       msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
+       msg.can_dlc = CAN_ERR_DLC;
+       for (j = 0; j < card->nbus; ++j) {
+               pbus = card->bus[j];
+               if (!pbus)
+                       continue;
+               if (!(mask_start & (1 << j)))
+                       continue;
+               pbus->can.state = CAN_STATE_ERROR_ACTIVE;
+               open_candev(pbus->netdev);
+               if (bus != pbus) {
+                       /* notify other busses on the restart */
+                       softing_rx(pbus->netdev, &msg, ktime_set(0, 0));
+                       ++pbus->can.can_stats.restarts;
+               }
+               netif_wake_queue(pbus->netdev);
        }
        }
+card_done:
+       mutex_unlock(&card->fw.lock);
        return 0;
 failed:
        return 0;
 failed:
+       dev_alert(card->dev, "firmware failed, going idle\n");
        softing_card_irq(card, 0);
        softing_reset_chip(card);
        softing_card_irq(card, 0);
        softing_reset_chip(card);
-       if (card->bus[0])
-               netif_carrier_off(card->bus[0]->netdev);
-       if (card->bus[1])
-               netif_carrier_off(card->bus[1]->netdev);
+       card->fw.failed = 1;
+       mutex_unlock(&card->fw.lock);
+       /* bring all other interfaces down */
+       for (j = 0; j < card->nbus; ++j) {
+               pbus = card->bus[j];
+               if (!pbus)
+                       continue;
+               dev_close(pbus->netdev);
+       }
+       return -EIO;
+
+failed_already:
+       mutex_unlock(&card->fw.lock);
        return -EIO;
 }
 
        return -EIO;
 }
 
@@ -665,21 +730,52 @@ int softing_default_output(struct softing *card, struct softing_priv *priv)
        }
 }
 
        }
 }
 
-u32 softing_time2usec(struct softing *card, u32 raw)
+ktime_t softing_raw2ktime(struct softing *card, u32 raw)
 {
 {
+       uint64_t ovf;
+       uint64_t rawl;
+       uint64_t expected;
+       ktime_t now;
+       ktime_t target;
+       ovf = 0x100000000ULL;
+       rawl = raw;
        /*TODO : don't loose higher order bits in computation */
        switch (card->desc->freq) {
        case 20:
        /*TODO : don't loose higher order bits in computation */
        switch (card->desc->freq) {
        case 20:
-               return raw * 4 / 5;
+               ovf = ovf * 4 / 5;
+               rawl = rawl * 4 / 5;
+               break;
        case 24:
        case 24:
-               return raw * 2 / 3;
+               ovf = ovf * 2 / 3;
+               rawl = rawl * 2 / 3;
+               break;
        case 25:
        case 25:
-               return raw * 16 / 25;
+               ovf = ovf * 16 / 25;
+               rawl = rawl * 16 / 25;
+               break;
        case 0:
        case 16:
        case 0:
        case 16:
+               break;
        default:
        default:
-               return raw;
+               /* return empty time */
+               return ktime_set(0, 0);
        }
        }
+       now = ktime_get_real();
+       expected = (ktime_us_delta(now, card->boot_time)) % ovf;
+       /*
+        * strange seuence for equation, but mind the 'unsigned-ness'
+        * the idea was to:
+        * if (expected < (rawl - (ovf / 2)))
+        * meaning: on wrap-around (occurs at 'ovf'), expected (actual time)
+        * may wrap around, altough rawl (receive time)
+        * is just before wrap-around. In that case, offset 'expected'
+        * note that expected can also be slightly earlier, as the card's
+        * timer starts a little (but unknown to me) after I mark 'boot_time'
+        */
+       if (rawl < (expected + (ovf / 2)))
+               /* now (expected) is always later than card stamp */
+               expected += ovf;
+       target = ktime_sub_us(now, (expected - rawl));
+       return target;
 }
 
 }
 
-
index a26cb1cb0c329d2c1a6657ef4ba3d00cb1cc5c56..88fa9f56df36d0f100f7850746d4d4b52515b749 100644 (file)
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
 
 #include "softing.h"
 
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
 
 #include "softing.h"
 
-/* this is the worst thing on the softing API
- * 2 busses are driven together, I don't know how
- * to recover a single of them.
- * Therefore, when one bus is modified, the other
- * is flushed too
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+#error This driver does not support Kernel versions < 2.6.23
+#endif
+
+/*
+ * test is a specific CAN netdev
+ * is online (ie. up 'n running, not sleeping, not busoff
  */
  */
-void softing_flush_echo_skb(struct softing_priv *priv)
+static inline int canif_is_active(struct net_device *netdev)
 {
 {
-       can_close_cleanup(priv->netdev);
-       priv->tx.pending = 0;
-       priv->tx.echo_put = 0;
-       priv->tx.echo_get = 0;
+       struct can_priv *can = netdev_priv(netdev);
+       if (!netif_running(netdev))
+               return 0;
+       return (can->state <= CAN_STATE_ERROR_PASSIVE);
 }
 
 }
 
-/*softing_unlocked_tx_run:*/
-/*trigger the tx queue-ing*/
-/*no locks are grabbed, so be sure to have the spin spinlock*/
+/* trigger the tx queue-ing */
 static int netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 static int netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct softing_priv *priv = (struct softing_priv *)netdev_priv(dev);
+       struct softing_priv *priv = netdev_priv(dev);
        struct softing *card = priv->card;
        int ret;
        int bhlock;
        struct softing *card = priv->card;
        int ret;
        int bhlock;
@@ -57,7 +57,6 @@ static int netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int fifo_wr;
        struct can_frame msg;
 
        unsigned int fifo_wr;
        struct can_frame msg;
 
-       ret = -ENOTTY;
        if (in_interrupt()) {
                bhlock = 0;
                spin_lock(&card->spin);
        if (in_interrupt()) {
                bhlock = 0;
                spin_lock(&card->spin);
@@ -65,28 +64,17 @@ static int netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
                bhlock = 1;
                spin_lock_bh(&card->spin);
        }
                bhlock = 1;
                spin_lock_bh(&card->spin);
        }
-       if (!card->fw.up) {
-               ret = -EIO;
+       ret = NETDEV_TX_BUSY;
+       if (!card->fw.up)
                goto xmit_done;
                goto xmit_done;
-       }
-       if (netif_carrier_ok(priv->netdev) <= 0) {
-               ret = -EBADF;
+       if (card->tx.pending >= TXMAX)
                goto xmit_done;
                goto xmit_done;
-       }
-       if (card->tx.pending >= TXMAX) {
-               ret = -EBUSY;
-               goto xmit_done;
-       }
-       if (priv->tx.pending >= CAN_ECHO_SKB_MAX) {
-               ret = -EBUSY;
+       if (priv->tx.pending >= CAN_ECHO_SKB_MAX)
                goto xmit_done;
                goto xmit_done;
-       }
        fifo_wr = card->dpram.tx->wr;
        fifo_wr = card->dpram.tx->wr;
-       if (fifo_wr == card->dpram.tx->rd) {
+       if (fifo_wr == card->dpram.tx->rd)
                /*fifo full */
                /*fifo full */
-               ret = -EAGAIN;
                goto xmit_done;
                goto xmit_done;
-       }
        memcpy(&msg, skb->data, sizeof(msg));
        ptr = &card->dpram.tx->fifo[fifo_wr][0];
        cmd = CMD_TX;
        memcpy(&msg, skb->data, sizeof(msg));
        ptr = &card->dpram.tx->fifo[fifo_wr][0];
        cmd = CMD_TX;
@@ -114,15 +102,15 @@ static int netdev_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 sizeof(card->dpram.tx->fifo[0]))
                fifo_wr = 0;
        card->dpram.tx->wr = fifo_wr;
                 sizeof(card->dpram.tx->fifo[0]))
                fifo_wr = 0;
        card->dpram.tx->wr = fifo_wr;
-       ret = 0;
+       card->tx.last_bus = priv->index;
        ++card->tx.pending;
        ++priv->tx.pending;
        can_put_echo_skb(skb, dev, priv->tx.echo_put);
        ++priv->tx.echo_put;
        if (priv->tx.echo_put >= CAN_ECHO_SKB_MAX)
                priv->tx.echo_put = 0;
        ++card->tx.pending;
        ++priv->tx.pending;
        can_put_echo_skb(skb, dev, priv->tx.echo_put);
        ++priv->tx.echo_put;
        if (priv->tx.echo_put >= CAN_ECHO_SKB_MAX)
                priv->tx.echo_put = 0;
-       /* clear pointer, so don't erase later */
-       skb = 0;
+       /* can_put_echo_skb() saves the skb, safe to return TX_OK */
+       ret = NETDEV_TX_OK;
 xmit_done:
        if (bhlock)
                spin_unlock_bh(&card->spin);
 xmit_done:
        if (bhlock)
                spin_unlock_bh(&card->spin);
@@ -138,10 +126,36 @@ xmit_done:
                        netif_stop_queue(bus->netdev);
                }
        }
                        netif_stop_queue(bus->netdev);
                }
        }
+       if (ret != NETDEV_TX_OK)
+               netif_stop_queue(dev);
+
+       return ret;
+}
+
+int softing_rx(struct net_device *netdev, const struct can_frame *msg,
+       ktime_t ktime)
+{
+       struct sk_buff *skb;
+       int ret;
+       struct net_device_stats *stats;
 
 
-       /* free skb, if not handled by the driver */
-       if (skb)
-               dev_kfree_skb(skb);
+       skb = dev_alloc_skb(sizeof(msg));
+       if (!skb)
+               return -ENOMEM;
+       skb->dev = netdev;
+       skb->protocol = htons(ETH_P_CAN);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       memcpy(skb_put(skb, sizeof(*msg)), msg, sizeof(*msg));
+       skb->tstamp = ktime;
+       ret = netif_rx(skb);
+       if (ret == NET_RX_DROP) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+               stats = can_get_stats(netdev);
+#else
+               stats = &netdev->stats;
+#endif
+               ++stats->rx_dropped;
+       }
        return ret;
 }
 
        return ret;
 }
 
@@ -149,12 +163,15 @@ static int softing_dev_svc_once(struct softing *card)
 {
        int j;
        struct softing_priv *bus;
 {
        int j;
        struct softing_priv *bus;
-       struct sk_buff *skb;
+       ktime_t ktime;
        struct can_frame msg;
 
        unsigned int fifo_rd;
        unsigned int cnt = 0;
        struct net_device_stats *stats;
        struct can_frame msg;
 
        unsigned int fifo_rd;
        unsigned int cnt = 0;
        struct net_device_stats *stats;
+       u8 *ptr;
+       u32 tmp;
+       u8 cmd;
 
        memset(&msg, 0, sizeof(msg));
        if (card->dpram.rx->lost_msg) {
 
        memset(&msg, 0, sizeof(msg));
        if (card->dpram.rx->lost_msg) {
@@ -164,184 +181,160 @@ static int softing_dev_svc_once(struct softing *card)
                msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
                msg.can_dlc = CAN_ERR_DLC;
                msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
                msg.can_dlc = CAN_ERR_DLC;
                msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-               /*service to both busses, we don't know which one generated */
+               /*
+                * service to all busses, we don't know which it was applicable
+                * but only service busses that are online
+                */
                for (j = 0; j < card->nbus; ++j) {
                        bus = card->bus[j];
                        if (!bus)
                                continue;
                for (j = 0; j < card->nbus; ++j) {
                        bus = card->bus[j];
                        if (!bus)
                                continue;
-                       if (!netif_carrier_ok(bus->netdev))
+                       if (!canif_is_active(bus->netdev))
+                               /* a dead bus has no overflows */
                                continue;
                                continue;
-                       ++bus->can.can_stats.data_overrun;
-                       skb = dev_alloc_skb(sizeof(msg));
-                       if (!skb)
-                               return -ENOMEM;
-                       skb->dev = bus->netdev;
-                       skb->protocol = htons(ETH_P_CAN);
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       memcpy(skb_put(skb, sizeof(msg)), &msg, sizeof(msg));
-                       if (netif_rx(skb))
-                               dev_kfree_skb_irq(skb);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+                       stats = can_get_stats(bus->netdev);
+#else
+                       stats = &bus->netdev->stats;
+#endif
+                       ++stats->rx_over_errors;
+                       softing_rx(bus->netdev, &msg, ktime_set(0, 0));
                }
                }
+               /* prepare for other use */
                memset(&msg, 0, sizeof(msg));
                ++cnt;
        }
 
        fifo_rd = card->dpram.rx->rd;
                memset(&msg, 0, sizeof(msg));
                ++cnt;
        }
 
        fifo_rd = card->dpram.rx->rd;
-       if (++fifo_rd >=
-                sizeof(card->dpram.rx->fifo) / sizeof(card->dpram.rx->fifo[0]))
+       if (++fifo_rd >= ARRAY_SIZE(card->dpram.rx->fifo))
                fifo_rd = 0;
                fifo_rd = 0;
-       if (card->dpram.rx->wr != fifo_rd) {
-               u8 *ptr;
-               u32 tmp;
-               u8 cmd;
-               int do_skb;
-
-               ptr = &card->dpram.rx->fifo[fifo_rd][0];
-
-               cmd = *ptr++;
-               if (cmd == 0xff) {
-                       /*not quite usefull, probably the card has got out */
-                       mod_alert("got cmd 0x%02x, I suspect the card is lost"
-                               , cmd);
-               }
-               /*mod_trace("0x%02x", cmd);*/
-               bus = card->bus[0];
-               if (cmd & CMD_BUS2)
-                       bus = card->bus[1];
+
+       if (card->dpram.rx->wr == fifo_rd)
+               return cnt;
+
+       ptr = &card->dpram.rx->fifo[fifo_rd][0];
+
+       cmd = *ptr++;
+       if (cmd == 0xff) {
+               /*not quite usefull, probably the card has got out */
+               dev_alert(card->dev, "got cmd 0x%02x,"
+                       " I suspect the card is lost\n", cmd);
+       }
+       /*mod_trace("0x%02x", cmd);*/
+       bus = card->bus[0];
+       if (cmd & CMD_BUS2)
+               bus = card->bus[1];
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
-               stats = can_get_stats(bus->netdev);
+       stats = can_get_stats(bus->netdev);
 #else
 #else
-               stats = &bus->netdev->stats;
+       stats = &bus->netdev->stats;
 #endif
 #endif
-               if (cmd & CMD_ERR) {
-                       u8 can_state;
-                       u8 state;
-                       state = *ptr++;
-
-                       msg.can_id = CAN_ERR_FLAG;
-                       msg.can_dlc = CAN_ERR_DLC;
-
-                       if (state & 0x80) {
-                               can_state = CAN_STATE_BUS_OFF;
-                               msg.can_id |= CAN_ERR_BUSOFF;
-                               state = 2;
-                       } else if (state & 0x60) {
-                               can_state = CAN_STATE_BUS_PASSIVE;
-                               msg.can_id |= CAN_ERR_BUSERROR;
-                               state = 1;
-                       } else {
-                               can_state = CAN_STATE_ACTIVE;
-                               state = 0;
-                               do_skb = 0;
-                       }
-                       /*update DPRAM */
-                       if (!bus->index)
-                               card->dpram.info->bus_state = state;
-                       else
-                               card->dpram.info->bus_state2 = state;
-                       /*timestamp */
-                       tmp =    (ptr[0] <<  0)
-                               |(ptr[1] <<  8)
-                               |(ptr[2] << 16)
-                               |(ptr[3] << 24);
-                       ptr += 4;
-                       /*msg.time = */ softing_time2usec(card, tmp);
-                       /*trigger dual port RAM */
-                       mb();
-                       card->dpram.rx->rd = fifo_rd;
-                       /*update internal status */
-                       if (can_state != bus->can.state) {
-                               bus->can.state = can_state;
-                               if (can_state == 1)
-                                       bus->can.can_stats.error_passive += 1;
-                       }
-                       bus->can.can_stats.bus_error += 1;
+       if (cmd & CMD_ERR) {
+               u8 can_state;
+               u8 state;
+               state = *ptr++;
 
 
-                       /*trigger socketcan */
-                       if (state == 2) {
+               msg.can_id = CAN_ERR_FLAG;
+               msg.can_dlc = CAN_ERR_DLC;
+
+               if (state & 0x80) {
+                       can_state = CAN_STATE_BUS_OFF;
+                       msg.can_id |= CAN_ERR_BUSOFF;
+                       state = 2;
+               } else if (state & 0x60) {
+                       can_state = CAN_STATE_ERROR_PASSIVE;
+                       msg.can_id |= CAN_ERR_BUSERROR;
+                       msg.data[1] = CAN_ERR_CRTL_TX_PASSIVE;
+                       state = 1;
+               } else {
+                       can_state = CAN_STATE_ERROR_ACTIVE;
+                       state = 0;
+                       msg.can_id |= CAN_ERR_BUSERROR;
+               }
+               /*update DPRAM */
+               if (!bus->index)
+                       card->dpram.info->bus_state = state;
+               else
+                       card->dpram.info->bus_state2 = state;
+               /*timestamp */
+               tmp = (ptr[0] <<  0) | (ptr[1] <<  8)
+                   | (ptr[2] << 16) | (ptr[3] << 24);
+               ptr += 4;
+               ktime = softing_raw2ktime(card, tmp);
+               /*trigger dual port RAM */
+               mb();
+               card->dpram.rx->rd = fifo_rd;
+
+               ++bus->can.can_stats.bus_error;
+               ++stats->rx_errors;
+               /*update internal status */
+               if (can_state != bus->can.state) {
+                       bus->can.state = can_state;
+                       if (can_state == CAN_STATE_ERROR_PASSIVE)
+                               ++bus->can.can_stats.error_passive;
+                       if (can_state == CAN_STATE_BUS_OFF) {
                                /* this calls can_close_cleanup() */
                                /* this calls can_close_cleanup() */
-                               softing_flush_echo_skb(bus);
                                can_bus_off(bus->netdev);
                                netif_stop_queue(bus->netdev);
                        }
                                can_bus_off(bus->netdev);
                                netif_stop_queue(bus->netdev);
                        }
-                       if ((state == CAN_STATE_BUS_OFF)
-                                || (state == CAN_STATE_BUS_PASSIVE)) {
-                               skb = dev_alloc_skb(sizeof(msg));
-                               if (!skb)
-                                       return -ENOMEM;
-                               skb->dev = bus->netdev;
-                               skb->protocol = htons(ETH_P_CAN);
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-                               memcpy(skb_put(skb, sizeof(msg)), &msg,
-                                                sizeof(msg));
-                               if (netif_rx(skb))
-                                       dev_kfree_skb_irq(skb);
-                       }
-               } else {
-                       if (cmd & CMD_RTR)
-                               msg.can_id |= CAN_RTR_FLAG;
-                       /* acknowledge, was tx msg
-                        * no real tx flag to set
-                       if (cmd & CMD_ACK) {
-                       }
-                        */
-                       msg.can_dlc = *ptr++;
-                       if (msg.can_dlc > 8)
-                               msg.can_dlc = 8;
-                       if (cmd & CMD_XTD) {
-                               msg.can_id |= CAN_EFF_FLAG;
-                               msg.can_id |=
-                                               (ptr[0] << 0)
-                                        | (ptr[1] << 8)
-                                        | (ptr[2] << 16)
-                                        | (ptr[3] << 24);
-                               ptr += 4;
-                       } else {
-                               msg.can_id |= (ptr[0] << 0) | (ptr[1] << 8);
-                               ptr += 2;
-                       }
-                       tmp = (ptr[0] << 0)
-                                | (ptr[1] << 8)
-                                | (ptr[2] << 16)
-                                | (ptr[3] << 24);
+                       /*trigger socketcan */
+                       softing_rx(bus->netdev, &msg, ktime);
+               }
+
+       } else {
+               if (cmd & CMD_RTR)
+                       msg.can_id |= CAN_RTR_FLAG;
+               /* acknowledge, was tx msg
+                * no real tx flag to set
+               if (cmd & CMD_ACK) {
+               }
+                */
+               msg.can_dlc = *ptr++;
+               if (msg.can_dlc > 8)
+                       msg.can_dlc = 8;
+               if (cmd & CMD_XTD) {
+                       msg.can_id |= CAN_EFF_FLAG;
+                       msg.can_id |= (ptr[0] <<  0) | (ptr[1] <<  8)
+                                   | (ptr[2] << 16) | (ptr[3] << 24);
                        ptr += 4;
                        ptr += 4;
-                       /*msg.time = */ softing_time2usec(card, tmp);
-                       memcpy_fromio(&msg.data[0], ptr, 8);
-                       ptr += 8;
-                       /*trigger dual port RAM */
-                       mb();
-                       card->dpram.rx->rd = fifo_rd;
-                       /*update socket */
-                       if (cmd & CMD_ACK) {
-                               can_get_echo_skb(bus->netdev, bus->tx.echo_get);
-                               ++bus->tx.echo_get;
-                               if (bus->tx.echo_get >= CAN_ECHO_SKB_MAX)
-                                       bus->tx.echo_get = 0;
-                               if (bus->tx.pending)
-                                       --bus->tx.pending;
-                               if (card->tx.pending)
-                                       --card->tx.pending;
-                               stats->tx_packets += 1;
-                               stats->tx_bytes += msg.can_dlc;
-                       } else {
-                               stats->rx_packets += 1;
-                               stats->rx_bytes += msg.can_dlc;
-                               bus->netdev->last_rx = jiffies;
-                               skb = dev_alloc_skb(sizeof(msg));
-                               if (skb) {
-                                       skb->dev = bus->netdev;
-                                       skb->protocol = htons(ETH_P_CAN);
-                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                                       memcpy(skb_put(skb, sizeof(msg)), &msg,
-                                                        sizeof(msg));
-                                       if (netif_rx(skb))
-                                               dev_kfree_skb_irq(skb);
-                               }
-                       }
+               } else {
+                       msg.can_id |= (ptr[0] << 0) | (ptr[1] << 8);
+                       ptr += 2;
+               }
+               tmp = (ptr[0] <<  0) | (ptr[1] <<  8)
+                   | (ptr[2] << 16) | (ptr[3] << 24);
+               ptr += 4;
+               ktime = softing_raw2ktime(card, tmp);
+               memcpy_fromio(&msg.data[0], ptr, 8);
+               ptr += 8;
+               /*trigger dual port RAM */
+               mb();
+               card->dpram.rx->rd = fifo_rd;
+               /*update socket */
+               if (cmd & CMD_ACK) {
+                       struct sk_buff *skb;
+                       skb = bus->can.echo_skb[bus->tx.echo_get];
+                       if (skb)
+                               skb->tstamp = ktime;
+                       can_get_echo_skb(bus->netdev, bus->tx.echo_get);
+                       ++bus->tx.echo_get;
+                       if (bus->tx.echo_get >= CAN_ECHO_SKB_MAX)
+                               bus->tx.echo_get = 0;
+                       if (bus->tx.pending)
+                               --bus->tx.pending;
+                       if (card->tx.pending)
+                               --card->tx.pending;
+                       ++stats->tx_packets;
+                       stats->tx_bytes += msg.can_dlc;
+               } else {
+                       ++stats->rx_packets;
+                       stats->rx_bytes += msg.can_dlc;
+                       bus->netdev->last_rx = jiffies;
+                       softing_rx(bus->netdev, &msg, ktime);
                }
                }
-               ++cnt;
        }
        }
+       ++cnt;
        return cnt;
 }
 
        return cnt;
 }
 
@@ -355,29 +348,22 @@ static void softing_dev_svc(unsigned long param)
        spin_lock(&card->spin);
        while (softing_dev_svc_once(card) > 0)
                ++card->irq.svc_count;
        spin_lock(&card->spin);
        while (softing_dev_svc_once(card) > 0)
                ++card->irq.svc_count;
+       spin_unlock(&card->spin);
        /*resume tx queue's */
        offset = card->tx.last_bus;
        for (j = 0; j < card->nbus; ++j) {
                if (card->tx.pending >= TXMAX)
                        break;
        /*resume tx queue's */
        offset = card->tx.last_bus;
        for (j = 0; j < card->nbus; ++j) {
                if (card->tx.pending >= TXMAX)
                        break;
-               bus = card->bus[(j + offset) % card->nbus];
-               if (netif_carrier_ok(bus->netdev))
-                       netif_wake_queue(bus->netdev);
-       }
-       spin_unlock(&card->spin);
-}
-
-static void card_seems_down(struct softing *card)
-{
-       /* free interrupt, but probably
-        * in wrong (interrupt) context
-       if (card->irq.requested) {
-               free_irq(card->irq.nr, card);
-               card->irq.requested = 0;
-               card->fw.up = 0;
+               bus = card->bus[(j + offset + 1) % card->nbus];
+               if (!bus)
+                       continue;
+               if (!canif_is_active(bus->netdev))
+                       /* it makes no sense to wake dead busses */
+                       continue;
+               if (bus->tx.pending >= CAN_ECHO_SKB_MAX)
+                       continue;
+               netif_wake_queue(bus->netdev);
        }
        }
-       */
-       mod_alert("I think the card is vanished");
 }
 
 static
 }
 
 static
@@ -388,7 +374,7 @@ irqreturn_t dev_interrupt_shared(int irq, void *dev_id)
        ir = card->dpram.virt[0xe02];
        card->dpram.virt[0xe02] = 0;
        if (card->dpram.rx->rd == 0xffff) {
        ir = card->dpram.virt[0xe02];
        card->dpram.virt[0xe02] = 0;
        if (card->dpram.rx->rd == 0xffff) {
-               card_seems_down(card);
+               dev_alert(card->dev, "I think the card is gone\n");
                return IRQ_NONE;
        }
        if (ir == 1) {
                return IRQ_NONE;
        }
        if (ir == 1) {
@@ -412,9 +398,8 @@ irqreturn_t dev_interrupt_nshared(int irq, void *dev_id)
        card->dpram.irq->to_host = 0;
        /* make sure we cleared it */
        wmb();
        card->dpram.irq->to_host = 0;
        /* make sure we cleared it */
        wmb();
-       mod_trace("0x%02x", irq_host);
        if (card->dpram.rx->rd == 0xffff) {
        if (card->dpram.rx->rd == 0xffff) {
-               card_seems_down(card);
+               dev_alert(card->dev, "I think the card is gone\n");
                return IRQ_NONE;
        }
        tasklet_schedule(&card->irq.bh);
                return IRQ_NONE;
        }
        tasklet_schedule(&card->irq.bh);
@@ -425,78 +410,45 @@ static int netdev_open(struct net_device *ndev)
 {
        struct softing_priv *priv = netdev_priv(ndev);
        struct softing *card = priv->card;
 {
        struct softing_priv *priv = netdev_priv(ndev);
        struct softing *card = priv->card;
-       int fw;
        int ret;
 
        int ret;
 
-       mod_trace("%s", ndev->name);
-       /* determine and set bittime */
-       ret = can_set_bittiming(ndev);
+       /* check or determine and set bittime */
+       ret = open_candev(ndev);
        if (ret)
        if (ret)
-               return ret;
-       if (mutex_lock_interruptible(&card->fw.lock))
-               return -ERESTARTSYS;
-       fw = card->fw.up;
-       if (fw)
-               softing_reinit(card
-                       , (card->bus[0] == priv) ? 1 : -1
-                       , (card->bus[1] == priv) ? 1 : -1);
-       mutex_unlock(&card->fw.lock);
-       if (!fw)
-               return -EIO;
+               goto failed;
+       ret = softing_cycle(card, priv, 1);
+       if (ret)
+               goto failed;
        netif_start_queue(ndev);
        return 0;
        netif_start_queue(ndev);
        return 0;
+failed:
+       return ret;
 }
 
 static int netdev_stop(struct net_device *ndev)
 {
        struct softing_priv *priv = netdev_priv(ndev);
        struct softing *card = priv->card;
 }
 
 static int netdev_stop(struct net_device *ndev)
 {
        struct softing_priv *priv = netdev_priv(ndev);
        struct softing *card = priv->card;
-       int fw;
+       int ret;
 
 
-       mod_trace("%s", ndev->name);
        netif_stop_queue(ndev);
        netif_stop_queue(ndev);
-       netif_carrier_off(ndev);
-       softing_flush_echo_skb(priv);
-       can_close_cleanup(ndev);
-       if (mutex_lock_interruptible(&card->fw.lock))
-               return -ERESTARTSYS;
-       fw = card->fw.up;
-       if (fw)
-               softing_reinit(card
-                       , (card->bus[0] == priv) ? 0 : -1
-                       , (card->bus[1] == priv) ? 0 : -1);
-       mutex_unlock(&card->fw.lock);
-       if (!fw)
-               return -EIO;
-       return 0;
-}
 
 
-static int candev_get_state(struct net_device *ndev, enum can_state *state)
-{
-       struct softing_priv *priv = netdev_priv(ndev);
-       mod_trace("%s", ndev->name);
-       if (priv->netdev->flags & IFF_UP)
-               *state = CAN_STATE_STOPPED;
-       else if (priv->can.state == CAN_STATE_STOPPED)
-               *state = CAN_STATE_STOPPED;
-       else
-               *state = CAN_STATE_ACTIVE;
-       return 0;
+       /* softing cycle does close_candev() */
+       ret = softing_cycle(card, priv, 0);
+       return ret;
 }
 
 static int candev_set_mode(struct net_device *ndev, enum can_mode mode)
 {
        struct softing_priv *priv = netdev_priv(ndev);
        struct softing *card = priv->card;
 }
 
 static int candev_set_mode(struct net_device *ndev, enum can_mode mode)
 {
        struct softing_priv *priv = netdev_priv(ndev);
        struct softing *card = priv->card;
-       mod_trace("%s %u", ndev->name, mode);
+       int ret;
+
        switch (mode) {
        case CAN_MODE_START:
        switch (mode) {
        case CAN_MODE_START:
-               /*recovery from busoff? */
-               if (mutex_lock_interruptible(&card->fw.lock))
-                       return -ERESTARTSYS;
-               softing_reinit(card, -1, -1);
-               mutex_unlock(&card->fw.lock);
-               break;
+               /* softing cycle does close_candev() */
+               ret = softing_cycle(card, priv, 1);
+               return ret;
        case CAN_MODE_STOP:
        case CAN_MODE_SLEEP:
                return -EOPNOTSUPP;
        case CAN_MODE_STOP:
        case CAN_MODE_SLEEP:
                return -EOPNOTSUPP;
@@ -525,9 +477,8 @@ int softing_card_irq(struct softing *card, int enable)
                        fn = dev_interrupt_shared;
                ret = request_irq(card->irq.nr, fn, flags, card->id.name, card);
                if (ret) {
                        fn = dev_interrupt_shared;
                ret = request_irq(card->irq.nr, fn, flags, card->id.name, card);
                if (ret) {
-                       mod_alert("%s, request_irq(%u) failed"
-                               , card->id.name, card->irq.nr
-                               );
+                       dev_alert(card->dev, "%s, request_irq(%u) failed\n",
+                               card->id.name, card->irq.nr);
                        return ret;
                }
                card->irq.requested = 1;
                        return ret;
                }
                card->irq.requested = 1;
@@ -538,7 +489,7 @@ int softing_card_irq(struct softing *card, int enable)
 static void shutdown_card(struct softing *card)
 {
        int fw_up = 0;
 static void shutdown_card(struct softing *card)
 {
        int fw_up = 0;
-       mod_trace("%s", card->id.name);
+       dev_dbg(card->dev, "%s()\n", __func__);
        if (mutex_lock_interruptible(&card->fw.lock))
                /* return -ERESTARTSYS*/;
        fw_up = card->fw.up;
        if (mutex_lock_interruptible(&card->fw.lock))
                /* return -ERESTARTSYS*/;
        fw_up = card->fw.up;
@@ -560,7 +511,12 @@ static void shutdown_card(struct softing *card)
 
 static int boot_card(struct softing *card)
 {
 
 static int boot_card(struct softing *card)
 {
-       mod_trace("%s", card->id.name);
+       unsigned char *lp;
+       static const unsigned char stream[] =
+               { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
+       unsigned char back[sizeof(stream)];
+       dev_dbg(card->dev, "%s()\n", __func__);
+
        if (mutex_lock_interruptible(&card->fw.lock))
                return -ERESTARTSYS;
        if (card->fw.up) {
        if (mutex_lock_interruptible(&card->fw.lock))
                return -ERESTARTSYS;
        if (card->fw.up) {
@@ -575,41 +531,24 @@ static int boot_card(struct softing *card)
        if (card->fn.reset)
                card->fn.reset(card, 1);
        /*test dp ram */
        if (card->fn.reset)
                card->fn.reset(card, 1);
        /*test dp ram */
-       if (card->dpram.virt) {
-               unsigned char *lp;
-               static const unsigned char stream[]
-               = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
-               unsigned char back[sizeof(stream)];
-               for (lp = card->dpram.virt;
-                         &lp[sizeof(stream)] <= card->dpram.end;
-                         lp += sizeof(stream)) {
-                       memcpy_toio(lp, stream, sizeof(stream));
-                       /* flush IO cache */
-                       mb();
-                       memcpy_fromio(back, lp, sizeof(stream));
-
-                       if (memcmp(back, stream, sizeof(stream))) {
-                               char line[3 * sizeof(stream)
-                                       / sizeof(stream[0]) + 1];
-                               char *pline = line;
-                               unsigned char *addr = lp;
-                               for (lp = back; lp < &back[sizeof(stream)
-                                               / sizeof(stream[0])]; ++lp)
-                                       pline += sprintf(pline, " %02x", *lp);
-
-                               mod_alert("write to dpram failed at 0x%p, %s"
-                                       , addr, line);
-                               goto open_failed;
-                       }
-               }
-               /*fill dpram with 0x55 */
-               /*for (lp = card->dpram.virt; lp <= card->dpram.end; ++lp) {
-                *lp = 0x55;
-                }*/
-               wmb();
-       } else {
+       if (!card->dpram.virt)
+               goto open_failed;
+       for (lp = card->dpram.virt; &lp[sizeof(stream)] <= card->dpram.end;
+               lp += sizeof(stream)) {
+
+               memcpy_toio(lp, stream, sizeof(stream));
+               /* flush IO cache */
+               mb();
+               memcpy_fromio(back, lp, sizeof(stream));
+
+               if (!memcmp(back, stream, sizeof(stream)))
+                       continue;
+               /* memory is not equal */
+               dev_alert(card->dev, "write to dpram failed at 0x%04lx\n",
+                       (unsigned long)(lp - card->dpram.virt));
                goto open_failed;
        }
                goto open_failed;
        }
+       wmb();
        /*load boot firmware */
        if (softing_load_fw(card->desc->boot.fw, card, card->dpram.virt,
                                 card->dpram.size,
        /*load boot firmware */
        if (softing_load_fw(card->desc->boot.fw, card, card->dpram.virt,
                                 card->dpram.size,
@@ -655,8 +594,8 @@ static int boot_card(struct softing *card)
        card->id.chip[0] = (u16) card->dpram.fct->param[4];
        card->id.chip[1] = (u16) card->dpram.fct->param[5];
 
        card->id.chip[0] = (u16) card->dpram.fct->param[4];
        card->id.chip[1] = (u16) card->dpram.fct->param[5];
 
-       mod_info("%s, card booted, "
-                       "serial %u, fw %u, hw %u, lic %u, chip (%u,%u)",
+       dev_info(card->dev, "card booted, type %s, "
+                       "serial %u, fw %u, hw %u, lic %u, chip (%u,%u)\n",
                  card->id.name, card->id.serial, card->id.fw, card->id.hw,
                  card->id.lic, card->id.chip[0], card->id.chip[1]);
 
                  card->id.name, card->id.serial, card->id.fw, card->id.hw,
                  card->id.lic, card->id.chip[0], card->id.chip[1]);
 
@@ -673,191 +612,13 @@ open_failed:
        return EINVAL;
 }
 
        return EINVAL;
 }
 
-/*sysfs stuff*/
-
-/* Because the struct softing may be used by pcmcia devices
- * as well as pci devices, * we have no clue how to get
- * from a struct device * towards the struct softing *.
- * It may go over a pci_device->priv or over a pcmcia_device->priv.
- * Therefore, provide the struct softing pointer within the attribute.
- * Then we don't need driver/bus specific things in these attributes
- */
-struct softing_attribute {
-       struct device_attribute dev;
-       ssize_t (*show) (struct softing *card, char *buf);
-       ssize_t (*store)(struct softing *card, const char *buf, size_t count);
-       struct softing *card;
-};
-
-static ssize_t rd_card_attr(struct device *dev, struct device_attribute *attr
-               , char *buf) {
-       struct softing_attribute *cattr
-               = container_of(attr, struct softing_attribute, dev);
-       return cattr->show ? cattr->show(cattr->card, buf) : 0;
-}
-static ssize_t wr_card_attr(struct device *dev, struct device_attribute *attr
-               , const char *buf, size_t count) {
-       struct softing_attribute *cattr
-               = container_of(attr, struct softing_attribute, dev);
-       return cattr->store ? cattr->store(cattr->card, buf, count) : 0;
-}
-
-#define declare_attr(_name, _mode, _show, _store) { \
-       .dev = { \
-               .attr = { \
-                       .name = __stringify(_name), \
-                       .mode = _mode, \
-               }, \
-               .show = rd_card_attr, \
-               .store = wr_card_attr, \
-       }, \
-       .show = _show, \
-       .store = _store, \
-}
-
-#define CARD_SHOW(name, member) \
-static ssize_t show_##name(struct softing *card, char *buf) { \
-       return sprintf(buf, "%u\n", card->member); \
-}
-CARD_SHOW(serial       , id.serial);
-CARD_SHOW(firmware     , id.fw);
-CARD_SHOW(hardware     , id.hw);
-CARD_SHOW(license      , id.lic);
-CARD_SHOW(freq         , id.freq);
-CARD_SHOW(txpending    , tx.pending);
-
-static const struct softing_attribute card_attr_proto [] = {
-       declare_attr(serial     , 0444, show_serial     , 0),
-       declare_attr(firmware   , 0444, show_firmware   , 0),
-       declare_attr(hardware   , 0444, show_hardware   , 0),
-       declare_attr(license    , 0444, show_license    , 0),
-       declare_attr(freq       , 0444, show_freq       , 0),
-       declare_attr(txpending  , 0644, show_txpending  , 0),
-};
-
-static int mk_card_sysfs(struct softing *card)
-{
-       int size;
-       int j;
-
-       size = sizeof(card_attr_proto)/sizeof(card_attr_proto[0]);
-       card->attr = kmalloc((size+1)*sizeof(card->attr[0]), GFP_KERNEL);
-       if (!card->attr)
-               goto attr_mem_failed;
-       memcpy(card->attr, card_attr_proto, size * sizeof(card->attr[0]));
-       memset(&card->attr[size], 0, sizeof(card->attr[0]));
-
-       card->grp  = kmalloc((size+1)*sizeof(card->grp [0]), GFP_KERNEL);
-       if (!card->grp)
-               goto grp_mem_failed;
-
-       for (j = 0; j < size; ++j) {
-               card->attr[j].card = card;
-               card->grp[j] = &card->attr[j].dev.attr;
-               if (!card->attr[j].show)
-                       card->attr[j].dev.attr.mode &= ~(S_IRUGO);
-               if (!card->attr[j].store)
-                       card->attr[j].dev.attr.mode &= ~(S_IWUGO);
-       }
-       card->grp[size] = 0;
-       card->sysfs.name        = "softing";
-       card->sysfs.attrs = card->grp;
-       if (sysfs_create_group(&card->dev->kobj, &card->sysfs) < 0)
-               goto sysfs_failed;
-
-       return 0;
-
-sysfs_failed:
-       kfree(card->grp);
-grp_mem_failed:
-       kfree(card->attr);
-attr_mem_failed:
-       return -1;
-}
-static void rm_card_sysfs(struct softing *card)
-{
-       sysfs_remove_group(&card->dev->kobj, &card->sysfs);
-       kfree(card->grp);
-       kfree(card->attr);
-}
-
-static ssize_t show_chip(struct device *dev
-               , struct device_attribute *attr, char *buf)
-{
-       struct net_device *ndev = to_net_dev(dev);
-       struct softing_priv *priv = netdev2softing(ndev);
-       return sprintf(buf, "%i\n", priv->chip);
-}
-
-static ssize_t show_output(struct device *dev
-               , struct device_attribute *attr, char *buf)
-{
-       struct net_device *ndev = to_net_dev(dev);
-       struct softing_priv *priv = netdev2softing(ndev);
-       return sprintf(buf, "0x%02x\n", priv->output);
-}
-
-static ssize_t store_output(struct device *dev
-               , struct device_attribute *attr
-               , const char *buf, size_t count)
-{
-       struct net_device *ndev = to_net_dev(dev);
-       struct softing_priv *priv = netdev2softing(ndev);
-       struct softing *card = priv->card;
-
-       u8 v = simple_strtoul(buf, NULL, 10) & 0xFFU;
-
-       if (mutex_lock_interruptible(&card->fw.lock))
-               return -ERESTARTSYS;
-       if (ndev->flags & IFF_UP) {
-               int j;
-               /* we will need a restart */
-               for (j = 0; j < card->nbus; ++j) {
-                       if (j == priv->index)
-                               /* me, myself & I */
-                               continue;
-                       if (card->bus[j]->netdev->flags & IFF_UP) {
-                               mutex_unlock(&card->fw.lock);
-                               return -EBUSY;
-                       }
-               }
-               priv->output = v;
-               softing_reinit(card, -1, -1);
-       } else {
-               priv->output = v;
-       }
-       mutex_unlock(&card->fw.lock);
-       return count;
-}
-/* TODO
- * the latest softing cards support sleep mode too
- */
-
-static const DEVICE_ATTR(chip, S_IRUGO, show_chip, 0);
-static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
-
-static const struct attribute *const netdev_sysfs_entries [] = {
-       &dev_attr_chip          .attr,
-       &dev_attr_output        .attr,
-       0,
-};
-static const struct attribute_group netdev_sysfs = {
-       .name  = 0,
-       .attrs = (struct attribute **)netdev_sysfs_entries,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops softing_netdev_ops = {
+       .ndo_open       = netdev_open,
+       .ndo_stop       = netdev_stop,
+       .ndo_start_xmit = netdev_start_xmit,
 };
 };
-
-static int mk_netdev_sysfs(struct softing_priv *priv)
-{
-       if (!priv->netdev->dev.kobj.sd) {
-               mod_alert("sysfs_create_group would fail");
-               return ENODEV;
-       }
-       return sysfs_create_group(&priv->netdev->dev.kobj, &netdev_sysfs);
-}
-static void rm_netdev_sysfs(struct softing_priv *priv)
-{
-       sysfs_remove_group(&priv->netdev->dev.kobj, &netdev_sysfs);
-}
+#endif
 
 static struct softing_priv *mk_netdev(struct softing *card, u16 chip_id)
 {
 
 static struct softing_priv *mk_netdev(struct softing *card, u16 chip_id)
 {
@@ -866,7 +627,7 @@ static struct softing_priv *mk_netdev(struct softing *card, u16 chip_id)
 
        ndev = alloc_candev(sizeof(*priv));
        if (!ndev) {
 
        ndev = alloc_candev(sizeof(*priv));
        if (!ndev) {
-               mod_alert("alloc_candev failed");
+               dev_alert(card->dev, "alloc_candev failed\n");
                return 0;
        }
        priv = netdev_priv(ndev);
                return 0;
        }
        priv = netdev_priv(ndev);
@@ -876,38 +637,37 @@ static struct softing_priv *mk_netdev(struct softing *card, u16 chip_id)
        priv->btr_const.brp_max = card->desc->max_brp;
        priv->btr_const.sjw_max = card->desc->max_sjw;
        priv->can.bittiming_const = &priv->btr_const;
        priv->btr_const.brp_max = card->desc->max_brp;
        priv->btr_const.sjw_max = card->desc->max_sjw;
        priv->can.bittiming_const = &priv->btr_const;
-       priv->can.bittiming.clock = 8000000;
-       priv->chip              = chip_id;
+       priv->can.clock.freq    = 8000000;
+       priv->chip              = chip_id;
        priv->output = softing_default_output(card, priv);
        SET_NETDEV_DEV(ndev, card->dev);
 
        ndev->flags |= IFF_ECHO;
        priv->output = softing_default_output(card, priv);
        SET_NETDEV_DEV(ndev, card->dev);
 
        ndev->flags |= IFF_ECHO;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       ndev->netdev_ops        = &softing_netdev_ops;
+#else
        ndev->open              = netdev_open;
        ndev->stop              = netdev_stop;
        ndev->hard_start_xmit   = netdev_start_xmit;
        ndev->open              = netdev_open;
        ndev->stop              = netdev_stop;
        ndev->hard_start_xmit   = netdev_start_xmit;
-       priv->can.do_get_state  = candev_get_state;
+#endif
        priv->can.do_set_mode   = candev_set_mode;
 
        return priv;
 }
 
        priv->can.do_set_mode   = candev_set_mode;
 
        return priv;
 }
 
-static void rm_netdev(struct softing_priv *priv)
-{
-       free_candev(priv->netdev);
-}
-
 static int reg_netdev(struct softing_priv *priv)
 {
        int ret;
 static int reg_netdev(struct softing_priv *priv)
 {
        int ret;
-       netif_carrier_off(priv->netdev);
        ret = register_candev(priv->netdev);
        if (ret) {
        ret = register_candev(priv->netdev);
        if (ret) {
-               mod_alert("%s, register failed", priv->card->id.name);
+               dev_alert(priv->card->dev, "%s, register failed\n",
+                       priv->card->id.name);
                goto reg_failed;
        }
                goto reg_failed;
        }
-       ret = mk_netdev_sysfs(priv);
+       ret = softing_bus_sysfs_create(priv);
        if (ret) {
        if (ret) {
-               mod_alert("%s, sysfs failed", priv->card->id.name);
+               dev_alert(priv->card->dev, "%s, sysfs failed\n",
+                       priv->card->id.name);
                goto sysfs_failed;
        }
        return 0;
                goto sysfs_failed;
        }
        return 0;
@@ -917,12 +677,6 @@ reg_failed:
        return EINVAL;
 }
 
        return EINVAL;
 }
 
-static void unreg_netdev(struct softing_priv *priv)
-{
-       rm_netdev_sysfs(priv);
-       unregister_candev(priv->netdev);
-}
-
 void rm_softing(struct softing *card)
 {
        int j;
 void rm_softing(struct softing *card)
 {
        int j;
@@ -931,11 +685,15 @@ void rm_softing(struct softing *card)
        shutdown_card(card);
 
        for (j = 0; j < card->nbus; ++j) {
        shutdown_card(card);
 
        for (j = 0; j < card->nbus; ++j) {
-               unreg_netdev(card->bus[j]);
-               rm_netdev(card->bus[j]);
+               if (!card->bus[j])
+                       continue;
+               softing_bus_sysfs_remove(card->bus[j]);
+               unregister_candev(card->bus[j]->netdev);
+               free_candev(card->bus[j]->netdev);
+               card->bus[j] = 0;
        }
 
        }
 
-       rm_card_sysfs(card);
+       softing_card_sysfs_remove(card);
 
        iounmap(card->dpram.virt);
 }
 
        iounmap(card->dpram.virt);
 }
@@ -952,16 +710,15 @@ int mk_softing(struct softing *card)
 
        card->desc = softing_lookup_desc(card->id.manf, card->id.prod);
        if (!card->desc) {
 
        card->desc = softing_lookup_desc(card->id.manf, card->id.prod);
        if (!card->desc) {
-               mod_alert("0x%04x:0x%04x not supported\n", card->id.manf,
-                         card->id.prod);
+               dev_alert(card->dev, "0x%04x:0x%04x not supported\n",
+                       card->id.manf, card->id.prod);
                goto lookup_failed;
        }
        card->id.name = card->desc->name;
                goto lookup_failed;
        }
        card->id.name = card->desc->name;
-       mod_trace("can (%s)", card->id.name);
 
        card->dpram.virt = ioremap(card->dpram.phys, card->dpram.size);
        if (!card->dpram.virt) {
 
        card->dpram.virt = ioremap(card->dpram.phys, card->dpram.size);
        if (!card->dpram.virt) {
-               mod_alert("dpram ioremap failed\n");
+               dev_alert(card->dev, "dpram ioremap failed\n");
                goto ioremap_failed;
        }
 
                goto ioremap_failed;
        }
 
@@ -980,51 +737,56 @@ int mk_softing(struct softing *card)
        if (card->fn.reset)
                card->fn.reset(card, 1);
        if (boot_card(card)) {
        if (card->fn.reset)
                card->fn.reset(card, 1);
        if (boot_card(card)) {
-               mod_alert("%s, failed to boot", card->id.name);
+               dev_alert(card->dev, "failed to boot\n");
                goto boot_failed;
        }
 
        /*only now, the chip's are known */
        card->id.freq = card->desc->freq * 1000000UL;
 
                goto boot_failed;
        }
 
        /*only now, the chip's are known */
        card->id.freq = card->desc->freq * 1000000UL;
 
-       if (mk_card_sysfs(card)) {
-               mod_alert("%s, sysfs failed", card->id.name);
+       if (softing_card_sysfs_create(card)) {
+               dev_alert(card->dev, "sysfs failed\n");
                goto sysfs_failed;
        }
 
        if (card->nbus > (sizeof(card->bus) / sizeof(card->bus[0]))) {
                card->nbus = sizeof(card->bus) / sizeof(card->bus[0]);
                goto sysfs_failed;
        }
 
        if (card->nbus > (sizeof(card->bus) / sizeof(card->bus[0]))) {
                card->nbus = sizeof(card->bus) / sizeof(card->bus[0]);
-               mod_alert("%s, going for %u busses", card->id.name, card->nbus);
+               dev_alert(card->dev, "have %u busses\n", card->nbus);
        }
 
        for (j = 0; j < card->nbus; ++j) {
                card->bus[j] = mk_netdev(card, card->id.chip[j]);
                if (!card->bus[j]) {
        }
 
        for (j = 0; j < card->nbus; ++j) {
                card->bus[j] = mk_netdev(card, card->id.chip[j]);
                if (!card->bus[j]) {
-                       mod_alert("%s: failed to make can[%i]", card->id.name,
-                                 j);
+                       dev_alert(card->dev, "failed to make can[%i]", j);
                        goto netdev_failed;
                }
                card->bus[j]->index = j;
        }
        for (j = 0; j < card->nbus; ++j) {
                if (reg_netdev(card->bus[j])) {
                        goto netdev_failed;
                }
                card->bus[j]->index = j;
        }
        for (j = 0; j < card->nbus; ++j) {
                if (reg_netdev(card->bus[j])) {
-                       mod_alert("%s: failed to register can[%i]",
-                                 card->id.name, j);
+                       dev_alert(card->dev,
+                               "failed to register can[%i]\n", j);
                        goto reg_failed;
                }
        }
                        goto reg_failed;
                }
        }
-       mod_trace("card initialised");
+       dev_info(card->dev, "card initialised\n");
        return 0;
 
 reg_failed:
        return 0;
 
 reg_failed:
-       for (j = 0; j < card->nbus; ++j)
-               unreg_netdev(card->bus[j]);
+       for (j = 0; j < card->nbus; ++j) {
+               if (!card->bus[j])
+                       continue;
+               softing_bus_sysfs_remove(card->bus[j]);
+               unregister_candev(card->bus[j]->netdev);
+       }
 netdev_failed:
        for (j = 0; j < card->nbus; ++j) {
 netdev_failed:
        for (j = 0; j < card->nbus; ++j) {
-               if (card->bus[j])
-                       rm_netdev(card->bus[j]);
+               if (!card->bus[j])
+                       continue;
+               free_candev(card->bus[j]->netdev);
+               card->bus[j] = 0;
        }
        }
-       rm_card_sysfs(card);
+       softing_card_sysfs_remove(card);
 sysfs_failed:
        shutdown_card(card);
 boot_failed:
 sysfs_failed:
        shutdown_card(card);
 boot_failed:
@@ -1040,13 +802,13 @@ EXPORT_SYMBOL(mk_softing);
 
 static int __init mod_start(void)
 {
 
 static int __init mod_start(void)
 {
-       mod_trace("");
+       printk(KERN_INFO "[%s] start\n", THIS_MODULE->name);
        return 0;
 }
 
 static void __exit mod_stop(void)
 {
        return 0;
 }
 
 static void __exit mod_stop(void)
 {
-       mod_trace("");
+       printk(KERN_INFO "[%s] stop\n", THIS_MODULE->name);
 }
 
 module_init(mod_start);
 }
 
 module_init(mod_start);
diff --git a/kernel/2.6/drivers/net/can/softing/softing_sysfs.c b/kernel/2.6/drivers/net/can/softing/softing_sysfs.c
new file mode 100644 (file)
index 0000000..8df59c0
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+* drivers/net/can/softing/softing_sysfs.c
+*
+* Copyright (C) 2009
+*
+* - Kurt Van Dijck, EIA Electronics
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the version 2 of the GNU General Public License
+* as published by the Free Software Foundation
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+
+#include "softing.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+#error This driver does not support Kernel versions < 2.6.23
+#endif
+
+/*sysfs stuff*/
+
+/* Because the struct softing may be used by pcmcia devices
+ * as well as pci devices, * we have no clue how to get
+ * from a struct device * towards the struct softing *.
+ * It may go over a pci_device->priv or over a pcmcia_device->priv.
+ * Therefore, provide the struct softing pointer within the attribute.
+ * Then we don't need driver/bus specific things in these attributes
+ */
+struct softing_attribute {
+       struct device_attribute dev;
+       ssize_t (*show) (struct softing *card, char *buf);
+       ssize_t (*store)(struct softing *card, const char *buf, size_t count);
+       struct softing *card;
+};
+
+static ssize_t rd_card_attr(struct device *dev, struct device_attribute *attr
+               , char *buf) {
+       struct softing_attribute *cattr
+               = container_of(attr, struct softing_attribute, dev);
+       return cattr->show ? cattr->show(cattr->card, buf) : 0;
+}
+static ssize_t wr_card_attr(struct device *dev, struct device_attribute *attr
+               , const char *buf, size_t count) {
+       struct softing_attribute *cattr
+               = container_of(attr, struct softing_attribute, dev);
+       return cattr->store ? cattr->store(cattr->card, buf, count) : 0;
+}
+
+#define declare_attr(_name, _mode, _show, _store) { \
+       .dev = { \
+               .attr = { \
+                       .name = __stringify(_name), \
+                       .mode = _mode, \
+               }, \
+               .show = rd_card_attr, \
+               .store = wr_card_attr, \
+       }, \
+       .show = _show, \
+       .store = _store, \
+}
+
+#define CARD_SHOW(name, member) \
+static ssize_t show_##name(struct softing *card, char *buf) { \
+       return sprintf(buf, "%u\n", card->member); \
+}
+CARD_SHOW(serial       , id.serial);
+CARD_SHOW(firmware     , id.fw);
+CARD_SHOW(hardware     , id.hw);
+CARD_SHOW(license      , id.lic);
+CARD_SHOW(freq         , id.freq);
+CARD_SHOW(txpending    , tx.pending);
+
+static const struct softing_attribute card_attr_proto[] = {
+       declare_attr(serial     , 0444, show_serial     , 0),
+       declare_attr(firmware   , 0444, show_firmware   , 0),
+       declare_attr(hardware   , 0444, show_hardware   , 0),
+       declare_attr(license    , 0444, show_license    , 0),
+       declare_attr(freq       , 0444, show_freq       , 0),
+       declare_attr(txpending  , 0644, show_txpending  , 0),
+};
+
+int softing_card_sysfs_create(struct softing *card)
+{
+       int size;
+       int j;
+
+       size = sizeof(card_attr_proto)/sizeof(card_attr_proto[0]);
+       card->attr = kmalloc((size+1)*sizeof(card->attr[0]), GFP_KERNEL);
+       if (!card->attr)
+               goto attr_mem_failed;
+       memcpy(card->attr, card_attr_proto, size * sizeof(card->attr[0]));
+       memset(&card->attr[size], 0, sizeof(card->attr[0]));
+
+       card->grp  = kmalloc((size+1)*sizeof(card->grp[0]), GFP_KERNEL);
+       if (!card->grp)
+               goto grp_mem_failed;
+
+       for (j = 0; j < size; ++j) {
+               card->attr[j].card = card;
+               card->grp[j] = &card->attr[j].dev.attr;
+               if (!card->attr[j].show)
+                       card->attr[j].dev.attr.mode &= ~(S_IRUGO);
+               if (!card->attr[j].store)
+                       card->attr[j].dev.attr.mode &= ~(S_IWUGO);
+       }
+       card->grp[size] = 0;
+       card->sysfs.name        = "softing";
+       card->sysfs.attrs = card->grp;
+       if (sysfs_create_group(&card->dev->kobj, &card->sysfs) < 0)
+               goto sysfs_failed;
+
+       return 0;
+
+sysfs_failed:
+       kfree(card->grp);
+grp_mem_failed:
+       kfree(card->attr);
+attr_mem_failed:
+       return -1;
+}
+void softing_card_sysfs_remove(struct softing *card)
+{
+       sysfs_remove_group(&card->dev->kobj, &card->sysfs);
+       kfree(card->grp);
+       kfree(card->attr);
+}
+
+static ssize_t show_chip(struct device *dev
+               , struct device_attribute *attr, char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+       return sprintf(buf, "%i\n", priv->chip);
+}
+
+static ssize_t show_output(struct device *dev
+               , struct device_attribute *attr, char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+       return sprintf(buf, "0x%02x\n", priv->output);
+}
+
+static ssize_t store_output(struct device *dev
+               , struct device_attribute *attr
+               , const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+       struct softing *card = priv->card;
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+       val &= 0xFF;
+
+       ret = mutex_lock_interruptible(&card->fw.lock);
+       if (ret)
+               return -ERESTARTSYS;
+       if (netif_running(ndev)) {
+               mutex_unlock(&card->fw.lock);
+               return -EBUSY;
+       }
+       priv->output = val;
+       mutex_unlock(&card->fw.lock);
+       return count;
+}
+/* TODO
+ * the latest softing cards support sleep mode too
+ */
+
+static const DEVICE_ATTR(chip, S_IRUGO, show_chip, 0);
+static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
+
+static const struct attribute *const netdev_sysfs_entries[] = {
+       &dev_attr_chip          .attr,
+       &dev_attr_output        .attr,
+       0,
+};
+static const struct attribute_group netdev_sysfs = {
+       .name  = 0,
+       .attrs = (struct attribute **)netdev_sysfs_entries,
+};
+
+int softing_bus_sysfs_create(struct softing_priv *priv)
+{
+       if (!priv->netdev->dev.kobj.sd) {
+               dev_alert(priv->card->dev, "sysfs_create_group would fail\n");
+               return ENODEV;
+       }
+       return sysfs_create_group(&priv->netdev->dev.kobj, &netdev_sysfs);
+}
+void softing_bus_sysfs_remove(struct softing_priv *priv)
+{
+       sysfs_remove_group(&priv->netdev->dev.kobj, &netdev_sysfs);
+}
+
index c2f7575faf9bca1f075d8cbafc6eba9abb4d9d16..9555eb28280d880547207f94cb022204600fccda 100644 (file)
 
 #include <linux/capability.h>
 #include <linux/kernel.h>
 
 #include <linux/capability.h>
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <net/sock.h>
 #include <linux/rtnetlink.h>
 
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <net/sock.h>
 #include <linux/rtnetlink.h>
 
-#include <linux/can.h>
-#include <linux/can/dev.h>
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
 
 #include "sysfs.h"
 
 
 #include "sysfs.h"
 
@@ -133,18 +134,13 @@ CAN_DEV_SHOW(ctrlmode, "0x%x\n");
 static int change_can_ctrlmode(struct net_device *dev, unsigned long ctrlmode)
 {
        struct can_priv *priv = netdev_priv(dev);
 static int change_can_ctrlmode(struct net_device *dev, unsigned long ctrlmode)
 {
        struct can_priv *priv = netdev_priv(dev);
-       int err = 0;
 
        if (priv->state != CAN_STATE_STOPPED)
                return -EBUSY;
 
 
        if (priv->state != CAN_STATE_STOPPED)
                return -EBUSY;
 
-       if (priv->do_set_ctrlmode)
-               err = priv->do_set_ctrlmode(dev, ctrlmode);
-
-       if (!err)
-               priv->ctrlmode = ctrlmode;
+       priv->ctrlmode = ctrlmode;
 
 
-       return err;
+       return 0;
 }
 
 static ssize_t store_can_ctrlmode(struct device *dev,
 }
 
 static ssize_t store_can_ctrlmode(struct device *dev,
@@ -199,6 +195,8 @@ static int change_can_restart_ms(struct net_device *dev, unsigned long ms)
 
        if (priv->restart_ms < 0)
                return -EOPNOTSUPP;
 
        if (priv->restart_ms < 0)
                return -EOPNOTSUPP;
+       if (priv->state != CAN_STATE_STOPPED)
+               return -EBUSY;
        priv->restart_ms = ms;
        return 0;
 }
        priv->restart_ms = ms;
        return 0;
 }
@@ -369,16 +367,20 @@ out:
        return ret;
 }
 
        return ret;
 }
 
-#define CAN_BT_ENTRY_RO(name)                                          \
-static ssize_t show_##name(struct device *d,                           \
-                          struct device_attribute *attr, char *buf)    \
-{                                                                      \
-       return can_bt_show(d, attr, buf,                                \
-                          offsetof(struct can_bittiming, name));       \
-}                                                                      \
-static DEVICE_ATTR(hw_##name, S_IRUGO, show_##name, NULL)
+static ssize_t fmt_can_clock(struct net_device *dev, char *buf)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       return sprintf(buf, "%d\n", priv->clock.freq);
+}
 
 
-CAN_BT_ENTRY_RO(clock);
+static ssize_t show_can_clock(struct device *d,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return can_dev_show(d, attr, buf, fmt_can_clock);
+}
+static DEVICE_ATTR(hw_clock, S_IRUGO, show_can_clock, NULL);
 
 #define CAN_BT_ENTRY(name)                                             \
 static ssize_t show_##name(struct device *d,                           \
 
 #define CAN_BT_ENTRY(name)                                             \
 static ssize_t show_##name(struct device *d,                           \
@@ -450,8 +452,8 @@ static ssize_t can_stat_show(const struct device *d,
 
        read_lock(&dev_base_lock);
        if (dev_isalive(dev))
 
        read_lock(&dev_base_lock);
        if (dev_isalive(dev))
-               ret = sprintf(buf, "%ld\n",
-                             *(unsigned long *)(((u8 *)stats) + offset));
+               ret = sprintf(buf, "%d\n",
+                             *(u32 *)(((u8 *)stats) + offset));
 
        read_unlock(&dev_base_lock);
        return ret;
 
        read_unlock(&dev_base_lock);
        return ret;
@@ -469,19 +471,17 @@ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
 CAN_STAT_ENTRY(error_warning);
 CAN_STAT_ENTRY(error_passive);
 
 CAN_STAT_ENTRY(error_warning);
 CAN_STAT_ENTRY(error_passive);
+CAN_STAT_ENTRY(bus_off);
 CAN_STAT_ENTRY(bus_error);
 CAN_STAT_ENTRY(arbitration_lost);
 CAN_STAT_ENTRY(bus_error);
 CAN_STAT_ENTRY(arbitration_lost);
-CAN_STAT_ENTRY(data_overrun);
-CAN_STAT_ENTRY(wakeup);
 CAN_STAT_ENTRY(restarts);
 
 static struct attribute *can_statistics_attrs[] = {
        &dev_attr_error_warning.attr,
        &dev_attr_error_passive.attr,
 CAN_STAT_ENTRY(restarts);
 
 static struct attribute *can_statistics_attrs[] = {
        &dev_attr_error_warning.attr,
        &dev_attr_error_passive.attr,
+       &dev_attr_bus_off.attr,
        &dev_attr_bus_error.attr,
        &dev_attr_arbitration_lost.attr,
        &dev_attr_bus_error.attr,
        &dev_attr_arbitration_lost.attr,
-       &dev_attr_data_overrun.attr,
-       &dev_attr_wakeup.attr,
        &dev_attr_restarts.attr,
        NULL
 };
        &dev_attr_restarts.attr,
        NULL
 };
index 059ec4ceab9c3d57671440fb2cfbc1c1851cb559..777a351da1c1068d72afebd78972da7e9cba9bee 100644 (file)
@@ -22,5 +22,6 @@
 
 void can_create_sysfs(struct net_device *dev);
 void can_remove_sysfs(struct net_device *dev);
 
 void can_create_sysfs(struct net_device *dev);
 void can_remove_sysfs(struct net_device *dev);
+int can_sample_point(struct can_bittiming *bt);
 
 #endif /* CAN_SYSFS_H */
 
 #endif /* CAN_SYSFS_H */
index bb0ff84d29d476fa7cc31342e53ab9fabcb85d6c..69cbeb9ddd6dd882dde5eeec5d0b51f1764ec6f4 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
-#include <linux/can.h>
+#include <socketcan/can.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
 #include <net/rtnetlink.h>
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
 #include <net/rtnetlink.h>
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 static __initdata const char banner[] =
 RCSID("$Id$");
 
 static __initdata const char banner[] =
index 5121cd634704749d8b6b3312606285292864f635..fbe374129cabc406bed2949ec08eb65b140e244b 100644 (file)
 #define CAN_DEV_H
 
 #include <linux/version.h>
 #define CAN_DEV_H
 
 #include <linux/version.h>
+#include <linux/can/netlink.h>
 #include <linux/can/error.h>
 
 #include <linux/can/error.h>
 
-/*
- * CAN bitrate and bit-timing
- */
-struct can_bittiming {
-       u32 bitrate;
-       u32 sample_point;
-       u32 tq;
-       u32 prop_seg;
-       u32 phase_seg1;
-       u32 phase_seg2;
-       u32 sjw;
-       u32 clock;
-       u32 brp;
-};
-
-struct can_bittiming_const {
-       u32 tseg1_min;
-       u32 tseg1_max;
-       u32 tseg2_min;
-       u32 tseg2_max;
-       u32 sjw_max;
-       u32 brp_min;
-       u32 brp_max;
-       u32 brp_inc;
-};
-
 /*
  * CAN mode
  */
 /*
  * CAN mode
  */
@@ -54,39 +29,6 @@ enum can_mode {
        CAN_MODE_SLEEP
 };
 
        CAN_MODE_SLEEP
 };
 
-/*
- * CAN controller mode
- */
-#define CAN_CTRLMODE_LOOPBACK  0x1
-#define CAN_CTRLMODE_LISTENONLY        0x2
-#define CAN_CTRLMODE_3_SAMPLES 0x4 /* Triple sampling mode */
-
-/*
- * CAN operational and error states
- */
-enum can_state {
-       CAN_STATE_ACTIVE = 0,
-       CAN_STATE_BUS_WARNING,
-       CAN_STATE_BUS_PASSIVE,
-       CAN_STATE_BUS_OFF,
-       CAN_STATE_STOPPED,
-       CAN_STATE_SLEEPING
-};
-
-/*
- * CAN device statistics
- */
-struct can_device_stats {
-       unsigned long error_warning;
-       unsigned long data_overrun;
-       unsigned long wakeup;
-       unsigned long bus_error;
-       unsigned long error_passive;
-       unsigned long arbitration_lost;
-       unsigned long restarts;
-       unsigned long bus_error_at_init;
-};
-
 /*
  * CAN common private data
  */
 /*
  * CAN common private data
  */
@@ -100,22 +42,20 @@ struct can_priv {
 
        struct can_bittiming bittiming;
        struct can_bittiming_const *bittiming_const;
 
        struct can_bittiming bittiming;
        struct can_bittiming_const *bittiming_const;
-
-       spinlock_t irq_lock;
+       struct can_clock clock;
 
        enum can_state state;
        u32 ctrlmode;
 
        int restart_ms;
 
        enum can_state state;
        u32 ctrlmode;
 
        int restart_ms;
-       struct timer_list timer;
+       struct timer_list restart_timer;
 
        struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX];
 
        int (*do_set_bittiming)(struct net_device *dev);
 
        struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX];
 
        int (*do_set_bittiming)(struct net_device *dev);
-       int (*do_get_state)(struct net_device *dev, enum can_state *state);
        int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
        int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
-       int (*do_set_ctrlmode)(struct net_device *dev, u32 ctrlmode);
-       int (*do_get_ctrlmode)(struct net_device *dev, u32 *ctrlmode);
+       int (*do_get_state)(const struct net_device *dev,
+                           enum can_state *state);
 };
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
 };
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
@@ -134,21 +74,18 @@ struct net_device_stats *can_get_stats(struct net_device *dev);
 
 struct net_device *alloc_candev(int sizeof_priv);
 void free_candev(struct net_device *dev);
 
 struct net_device *alloc_candev(int sizeof_priv);
 void free_candev(struct net_device *dev);
+
+int open_candev(struct net_device *dev);
+void close_candev(struct net_device *dev);
+
 int register_candev(struct net_device *dev);
 void unregister_candev(struct net_device *dev);
 
 int register_candev(struct net_device *dev);
 void unregister_candev(struct net_device *dev);
 
-int can_set_bittiming(struct net_device *dev);
-
 int can_restart_now(struct net_device *dev);
 int can_restart_now(struct net_device *dev);
-
 void can_bus_off(struct net_device *dev);
 
 void can_bus_off(struct net_device *dev);
 
-void can_close_cleanup(struct net_device *dev);
-
 void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx);
 void can_get_echo_skb(struct net_device *dev, int idx);
 void can_free_echo_skb(struct net_device *dev, int idx);
 
 void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx);
 void can_get_echo_skb(struct net_device *dev, int idx);
 void can_free_echo_skb(struct net_device *dev, int idx);
 
-int can_sample_point(struct can_bittiming *bt);
-
 #endif /* CAN_DEV_H */
 #endif /* CAN_DEV_H */
diff --git a/kernel/2.6/include/linux/can/netlink.h b/kernel/2.6/include/linux/can/netlink.h
new file mode 100644 (file)
index 0000000..fb29cdb
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * linux/can/netlink.h
+ *
+ * Definitions for the CAN netlink interface
+ *
+ * $Id: dev.h 939 2009-02-14 14:30:19Z wolf $
+ *
+ * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_NETLINK_H
+#define CAN_NETLINK_H
+
+#include <linux/types.h>
+
+/*
+ * CAN bit-timing parameters
+ *
+ * For futher information, please read chapter "8 BIT TIMING
+ * REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
+ * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
+ */
+struct can_bittiming {
+       __u32 bitrate;          /* Bit-rate in bits/second */
+       __u32 sample_point;     /* Sample point in one-tenth of a percent */
+       __u32 tq;               /* Time quanta (TQ) in nanoseconds */
+       __u32 prop_seg;         /* Propagation segment in TQs */
+       __u32 phase_seg1;       /* Phase buffer segment 1 in TQs */
+       __u32 phase_seg2;       /* Phase buffer segment 2 in TQs */
+       __u32 sjw;              /* Synchronisation jump width in TQs */
+       __u32 brp;              /* Bit-rate prescaler */
+};
+
+/*
+ * CAN harware-dependent bit-timing constant
+ *
+ * Used for calculating and checking bit-timing parameters
+ */
+struct can_bittiming_const {
+       char name[16];          /* Name of the CAN controller hardware */
+       __u32 tseg1_min;        /* Time segement 1 = prop_seg + phase_seg1 */
+       __u32 tseg1_max;
+       __u32 tseg2_min;        /* Time segement 2 = phase_seg2 */
+       __u32 tseg2_max;
+       __u32 sjw_max;          /* Synchronisation jump width */
+       __u32 brp_min;          /* Bit-rate prescaler */
+       __u32 brp_max;
+       __u32 brp_inc;
+};
+
+/*
+ * CAN clock parameters
+ */
+struct can_clock {
+       __u32 freq;             /* CAN system clock frequency in Hz */
+};
+
+/*
+ * CAN operational and error states
+ */
+enum can_state {
+       CAN_STATE_ERROR_ACTIVE = 0,     /* RX/TX error count < 96 */
+       CAN_STATE_ERROR_WARNING,        /* RX/TX error count < 128 */
+       CAN_STATE_ERROR_PASSIVE,        /* RX/TX error count < 256 */
+       CAN_STATE_BUS_OFF,              /* RX/TX error count >= 256 */
+       CAN_STATE_STOPPED,              /* Device is stopped */
+       CAN_STATE_SLEEPING,             /* Device is sleeping */
+       CAN_STATE_MAX
+};
+
+/*
+ * CAN controller mode
+ */
+struct can_ctrlmode {
+       __u32 mask;
+       __u32 flags;
+};
+
+#define CAN_CTRLMODE_LOOPBACK  0x1     /* Loopback mode */
+#define CAN_CTRLMODE_LISTENONLY        0x2     /* Listen-only mode */
+#define CAN_CTRLMODE_3_SAMPLES 0x4     /* Triple sampling mode */
+
+/*
+ * CAN device statistics
+ */
+struct can_device_stats {
+       __u32 bus_error;        /* Bus errors */
+       __u32 error_warning;    /* Changes to error warning state */
+       __u32 error_passive;    /* Changes to error passive state */
+       __u32 bus_off;          /* Changes to bus off state */
+       __u32 arbitration_lost; /* Arbitration lost errors */
+       __u32 restarts;         /* CAN controller re-starts */
+};
+
+/*
+ * CAN netlink interface
+ */
+enum {
+       IFLA_CAN_UNSPEC,
+       IFLA_CAN_BITTIMING,
+       IFLA_CAN_BITTIMING_CONST,
+       IFLA_CAN_CLOCK,
+       IFLA_CAN_STATE,
+       IFLA_CAN_CTRLMODE,
+       IFLA_CAN_RESTART_MS,
+       IFLA_CAN_RESTART,
+       __IFLA_CAN_MAX
+};
+
+#define IFLA_CAN_MAX   (__IFLA_CAN_MAX - 1)
+
+#endif /* CAN_NETLINK_H */
index 37966e630ff50e8dc4282959da910008ef47d2c6..01ee2aeb048df36e535982e20b30c7b004e1a5c9 100644 (file)
@@ -13,6 +13,7 @@
 #define OCR_MODE_TEST     0x01
 #define OCR_MODE_NORMAL   0x02
 #define OCR_MODE_CLOCK    0x03
 #define OCR_MODE_TEST     0x01
 #define OCR_MODE_NORMAL   0x02
 #define OCR_MODE_CLOCK    0x03
+#define OCR_MODE_MASK     0x07
 #define OCR_TX0_INVERT    0x04
 #define OCR_TX0_PULLDOWN  0x08
 #define OCR_TX0_PULLUP    0x10
 #define OCR_TX0_INVERT    0x04
 #define OCR_TX0_PULLDOWN  0x08
 #define OCR_TX0_PULLUP    0x10
@@ -21,6 +22,8 @@
 #define OCR_TX1_PULLDOWN  0x40
 #define OCR_TX1_PULLUP    0x80
 #define OCR_TX1_PUSHPULL  0xc0
 #define OCR_TX1_PULLDOWN  0x40
 #define OCR_TX1_PULLUP    0x80
 #define OCR_TX1_PUSHPULL  0xc0
+#define OCR_TX_MASK       0xfc
+#define OCR_TX_SHIFT      2
 
 struct sja1000_platform_data {
        u32 clock;      /* CAN bus oscillator frequency in Hz */
 
 struct sja1000_platform_data {
        u32 clock;      /* CAN bus oscillator frequency in Hz */
diff --git a/kernel/2.6/include/socketcan/can.h b/kernel/2.6/include/socketcan/can.h
new file mode 100644 (file)
index 0000000..7c9b05d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * socketcan/can.h
+ *
+ * Definitions for CAN network layer (socket addr / CAN frame / CAN filter)
+ *
+ * $Id$
+ *
+ * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ *          Urs Thuermann   <urs.thuermann@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_H
+#define CAN_H
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/* controller area network (CAN) kernel definitions */
+
+/* special address description flags for the CAN_ID */
+#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
+#define CAN_ERR_FLAG 0x20000000U /* error frame */
+
+/* valid bits in CAN ID for frame formats */
+#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
+#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
+#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
+
+/*
+ * Controller Area Network Identifier structure
+ *
+ * bit 0-28    : CAN identifier (11/29 bit)
+ * bit 29      : error frame flag (0 = data frame, 1 = error frame)
+ * bit 30      : remote transmission request flag (1 = rtr frame)
+ * bit 31      : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+typedef __u32 canid_t;
+
+/*
+ * Controller Area Network Error Frame Mask structure
+ *
+ * bit 0-28    : error class mask (see include/socketcan/can/error.h)
+ * bit 29-31   : set to zero
+ */
+typedef __u32 can_err_mask_t;
+
+/**
+ * struct can_frame - basic CAN frame structure
+ * @can_id:  the CAN ID of the frame and CAN_*_FLAG flags, see above.
+ * @can_dlc: the data length field of the CAN frame
+ * @data:    the CAN frame payload.
+ */
+struct can_frame {
+       canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+       __u8    can_dlc; /* data length code: 0 .. 8 */
+       __u8    data[8] __attribute__((aligned(8)));
+};
+
+/* particular protocols of the protocol family PF_CAN */
+#define CAN_RAW                1 /* RAW sockets */
+#define CAN_BCM                2 /* Broadcast Manager */
+#define CAN_TP16       3 /* VAG Transport Protocol v1.6 */
+#define CAN_TP20       4 /* VAG Transport Protocol v2.0 */
+#define CAN_MCNET      5 /* Bosch MCNet */
+#define CAN_ISOTP      6 /* ISO 15765-2 Transport Protocol */
+#define CAN_NPROTO     7
+
+#define SOL_CAN_BASE 100
+
+/**
+ * struct sockaddr_can - the sockaddr structure for CAN sockets
+ * @can_family:  address family number AF_CAN.
+ * @can_ifindex: CAN network interface index.
+ * @can_addr:    protocol specific address information
+ */
+struct sockaddr_can {
+       sa_family_t can_family;
+       int         can_ifindex;
+       union {
+               /* transport protocol class address information (e.g. ISOTP) */
+               struct { canid_t rx_id, tx_id; } tp;
+
+               /* reserved for future CAN protocols address information */
+       } can_addr;
+};
+
+/**
+ * struct can_filter - CAN ID based filter in can_register().
+ * @can_id:   relevant bits of CAN ID which are not masked out.
+ * @can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *          <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error frames (CAN_ERR_FLAG bit set in mask).
+ */
+struct can_filter {
+       canid_t can_id;
+       canid_t can_mask;
+};
+
+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+
+#endif /* CAN_H */
diff --git a/kernel/2.6/include/socketcan/can/bcm.h b/kernel/2.6/include/socketcan/can/bcm.h
new file mode 100644 (file)
index 0000000..30603ca
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * socketcan/can/bcm.h
+ *
+ * Definitions for CAN Broadcast Manager (BCM)
+ *
+ * $Id$
+ *
+ * Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_BCM_H
+#define CAN_BCM_H
+
+/**
+ * struct bcm_msg_head - head of messages to/from the broadcast manager
+ * @opcode:    opcode, see enum below.
+ * @flags:     special flags, see below.
+ * @count:     number of frames to send before changing interval.
+ * @ival1:     interval for the first @count frames.
+ * @ival2:     interval for the following frames.
+ * @can_id:    CAN ID of frames to be sent or received.
+ * @nframes:   number of frames appended to the message head.
+ * @frames:    array of CAN frames.
+ */
+struct bcm_msg_head {
+       __u32 opcode;
+       __u32 flags;
+       __u32 count;
+       struct timeval ival1, ival2;
+       canid_t can_id;
+       __u32 nframes;
+       struct can_frame frames[0];
+};
+
+enum {
+       TX_SETUP = 1,   /* create (cyclic) transmission task */
+       TX_DELETE,      /* remove (cyclic) transmission task */
+       TX_READ,        /* read properties of (cyclic) transmission task */
+       TX_SEND,        /* send one CAN frame */
+       RX_SETUP,       /* create RX content filter subscription */
+       RX_DELETE,      /* remove RX content filter subscription */
+       RX_READ,        /* read properties of RX content filter subscription */
+       TX_STATUS,      /* reply to TX_READ request */
+       TX_EXPIRED,     /* notification on performed transmissions (count=0) */
+       RX_STATUS,      /* reply to RX_READ request */
+       RX_TIMEOUT,     /* cyclic message is absent */
+       RX_CHANGED      /* updated CAN frame (detected content change) */
+};
+
+#define SETTIMER            0x0001
+#define STARTTIMER          0x0002
+#define TX_COUNTEVT         0x0004
+#define TX_ANNOUNCE         0x0008
+#define TX_CP_CAN_ID        0x0010
+#define RX_FILTER_ID        0x0020
+#define RX_CHECK_DLC        0x0040
+#define RX_NO_AUTOTIMER     0x0080
+#define RX_ANNOUNCE_RESUME  0x0100
+#define TX_RESET_MULTI_IDX  0x0200
+#define RX_RTR_FRAME        0x0400
+
+#endif /* CAN_BCM_H */
diff --git a/kernel/2.6/include/socketcan/can/core.h b/kernel/2.6/include/socketcan/can/core.h
new file mode 100644 (file)
index 0000000..23ce1c9
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * socketcan/can/core.h
+ *
+ * Protoypes and definitions for CAN protocol modules using the PF_CAN core
+ *
+ * $Id$
+ *
+ * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ *          Urs Thuermann   <urs.thuermann@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_CORE_H
+#define CAN_CORE_H
+
+#include <socketcan/can.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#define CAN_VERSION "20090105"
+
+/* increment this number each time you change some user-space interface */
+#define CAN_ABI_VERSION "8"
+
+#define CAN_VERSION_STRING "rev " CAN_VERSION " abi " CAN_ABI_VERSION
+
+#define DNAME(dev) ((dev) ? (dev)->name : "any")
+
+/**
+ * struct can_proto - CAN protocol structure
+ * @type:       type argument in socket() syscall, e.g. SOCK_DGRAM.
+ * @protocol:   protocol number in socket() syscall.
+ * @capability: capability needed to open the socket, or -1 for no restriction.
+ * @ops:        pointer to struct proto_ops for sock->ops.
+ * @prot:       pointer to struct proto structure.
+ */
+struct can_proto {
+       int              type;
+       int              protocol;
+       int              capability;
+       struct proto_ops *ops;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+       struct proto     *prot;
+#else
+       struct module    *owner;
+       int              (*init)(struct sock *sk);
+       size_t           obj_size;
+#endif
+};
+
+/* function prototypes for the CAN networklayer core (af_can.c) */
+
+extern int  can_proto_register(struct can_proto *cp);
+extern void can_proto_unregister(struct can_proto *cp);
+
+extern int  can_rx_register(struct net_device *dev, canid_t can_id,
+                           canid_t mask,
+                           void (*func)(struct sk_buff *, void *),
+                           void *data, char *ident);
+
+extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
+                             canid_t mask,
+                             void (*func)(struct sk_buff *, void *),
+                             void *data);
+
+extern int can_send(struct sk_buff *skb, int loop);
+
+#endif /* CAN_CORE_H */
diff --git a/kernel/2.6/include/socketcan/can/dev.h b/kernel/2.6/include/socketcan/can/dev.h
new file mode 100644 (file)
index 0000000..933a575
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * socketcan/can/dev.h
+ *
+ * Definitions for the CAN network device driver interface
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006 Andrey Volkov <avolkov@varma-el.com>
+ *               Varma Electronics Oy
+ *
+ * Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ */
+
+#ifndef CAN_DEV_H
+#define CAN_DEV_H
+
+#include <linux/version.h>
+#include <socketcan/can/netlink.h>
+#include <socketcan/can/error.h>
+
+/*
+ * CAN mode
+ */
+enum can_mode {
+       CAN_MODE_STOP = 0,
+       CAN_MODE_START,
+       CAN_MODE_SLEEP
+};
+
+/*
+ * CAN common private data
+ */
+#define CAN_ECHO_SKB_MAX  4
+
+struct can_priv {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       struct net_device_stats net_stats;
+#endif
+       struct can_device_stats can_stats;
+
+       struct can_bittiming bittiming;
+       struct can_bittiming_const *bittiming_const;
+       struct can_clock clock;
+
+       enum can_state state;
+       u32 ctrlmode;
+
+       int restart_ms;
+       struct timer_list restart_timer;
+
+       struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX];
+
+       int (*do_set_bittiming)(struct net_device *dev);
+       int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
+       int (*do_get_state)(const struct net_device *dev,
+                           enum can_state *state);
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+#define ND2D(_ndev)    (_ndev->class_dev.dev)
+#else
+#define ND2D(_ndev)    (_ndev->dev.parent)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+#define IFF_ECHO IFF_LOOPBACK
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+struct net_device_stats *can_get_stats(struct net_device *dev);
+#endif
+
+struct net_device *alloc_candev(int sizeof_priv);
+void free_candev(struct net_device *dev);
+
+int open_candev(struct net_device *dev);
+void close_candev(struct net_device *dev);
+
+int register_candev(struct net_device *dev);
+void unregister_candev(struct net_device *dev);
+
+int can_restart_now(struct net_device *dev);
+void can_bus_off(struct net_device *dev);
+
+void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx);
+void can_get_echo_skb(struct net_device *dev, int idx);
+void can_free_echo_skb(struct net_device *dev, int idx);
+
+#endif /* CAN_DEV_H */
diff --git a/kernel/2.6/include/socketcan/can/error.h b/kernel/2.6/include/socketcan/can/error.h
new file mode 100644 (file)
index 0000000..44176c2
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * socketcan/can/error.h
+ *
+ * Definitions of the CAN error frame to be filtered and passed to the user.
+ *
+ * $Id$
+ *
+ * Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_ERROR_H
+#define CAN_ERROR_H
+
+#define CAN_ERR_DLC 8 /* dlc for error frames */
+
+/* error class (mask) in can_id */
+#define CAN_ERR_TX_TIMEOUT   0x00000001U /* TX timeout (by netdevice driver) */
+#define CAN_ERR_LOSTARB      0x00000002U /* lost arbitration    / data[0]    */
+#define CAN_ERR_CRTL         0x00000004U /* controller problems / data[1]    */
+#define CAN_ERR_PROT         0x00000008U /* protocol violations / data[2..3] */
+#define CAN_ERR_TRX          0x00000010U /* transceiver status  / data[4]    */
+#define CAN_ERR_ACK          0x00000020U /* received no ACK on transmission */
+#define CAN_ERR_BUSOFF       0x00000040U /* bus off */
+#define CAN_ERR_BUSERROR     0x00000080U /* bus error (may flood!) */
+#define CAN_ERR_RESTARTED    0x00000100U /* controller restarted */
+
+/* arbitration lost in bit ... / data[0] */
+#define CAN_ERR_LOSTARB_UNSPEC   0x00 /* unspecified */
+                                     /* else bit number in bitstream */
+
+/* error status of CAN-controller / data[1] */
+#define CAN_ERR_CRTL_UNSPEC      0x00 /* unspecified */
+#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */
+#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */
+#define CAN_ERR_CRTL_RX_WARNING  0x04 /* reached warning level for RX errors */
+#define CAN_ERR_CRTL_TX_WARNING  0x08 /* reached warning level for TX errors */
+#define CAN_ERR_CRTL_RX_PASSIVE  0x10 /* reached error passive status RX */
+#define CAN_ERR_CRTL_TX_PASSIVE  0x20 /* reached error passive status TX */
+                                     /* (at least one error counter exceeds */
+                                     /* the protocol-defined level of 127)  */
+
+/* error in CAN protocol (type) / data[2] */
+#define CAN_ERR_PROT_UNSPEC      0x00 /* unspecified */
+#define CAN_ERR_PROT_BIT         0x01 /* single bit error */
+#define CAN_ERR_PROT_FORM        0x02 /* frame format error */
+#define CAN_ERR_PROT_STUFF       0x04 /* bit stuffing error */
+#define CAN_ERR_PROT_BIT0        0x08 /* unable to send dominant bit */
+#define CAN_ERR_PROT_BIT1        0x10 /* unable to send recessive bit */
+#define CAN_ERR_PROT_OVERLOAD    0x20 /* bus overload */
+#define CAN_ERR_PROT_ACTIVE      0x40 /* active error announcement */
+#define CAN_ERR_PROT_TX          0x80 /* error occured on transmission */
+
+/* error in CAN protocol (location) / data[3] */
+#define CAN_ERR_PROT_LOC_UNSPEC  0x00 /* unspecified */
+#define CAN_ERR_PROT_LOC_SOF     0x03 /* start of frame */
+#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */
+#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/
+#define CAN_ERR_PROT_LOC_SRTR    0x04 /* substitute RTR (SFF: RTR) */
+#define CAN_ERR_PROT_LOC_IDE     0x05 /* identifier extension */
+#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */
+#define CAN_ERR_PROT_LOC_ID12_05 0x0F /* ID bits 12-5 */
+#define CAN_ERR_PROT_LOC_ID04_00 0x0E /* ID bits 4-0 */
+#define CAN_ERR_PROT_LOC_RTR     0x0C /* RTR */
+#define CAN_ERR_PROT_LOC_RES1    0x0D /* reserved bit 1 */
+#define CAN_ERR_PROT_LOC_RES0    0x09 /* reserved bit 0 */
+#define CAN_ERR_PROT_LOC_DLC     0x0B /* data length code */
+#define CAN_ERR_PROT_LOC_DATA    0x0A /* data section */
+#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */
+#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */
+#define CAN_ERR_PROT_LOC_ACK     0x19 /* ACK slot */
+#define CAN_ERR_PROT_LOC_ACK_DEL 0x1B /* ACK delimiter */
+#define CAN_ERR_PROT_LOC_EOF     0x1A /* end of frame */
+#define CAN_ERR_PROT_LOC_INTERM  0x12 /* intermission */
+
+/* error status of CAN-transceiver / data[4] */
+/*                                             CANH CANL */
+#define CAN_ERR_TRX_UNSPEC             0x00 /* 0000 0000 */
+#define CAN_ERR_TRX_CANH_NO_WIRE       0x04 /* 0000 0100 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_BAT  0x05 /* 0000 0101 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_VCC  0x06 /* 0000 0110 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_GND  0x07 /* 0000 0111 */
+#define CAN_ERR_TRX_CANL_NO_WIRE       0x40 /* 0100 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_BAT  0x50 /* 0101 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_VCC  0x60 /* 0110 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_GND  0x70 /* 0111 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */
+
+/* controller specific additional information / data[5..7] */
+
+#endif /* CAN_ERROR_H */
diff --git a/kernel/2.6/include/socketcan/can/ioctl.h b/kernel/2.6/include/socketcan/can/ioctl.h
new file mode 100644 (file)
index 0000000..75c83d8
--- /dev/null
@@ -0,0 +1,99 @@
+
+/*
+ * socketcan/can/ioctl.h
+ *
+ * Definitions for CAN controller setup (work in progress)
+ *
+ * $Id$
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_IOCTL_H
+#define CAN_IOCTL_H
+
+#include <linux/sockios.h>
+
+/*
+ * CAN bitrate
+ */
+#define CAN_BITRATE_UNCONFIGURED       ((__u32) 0xFFFFFFFFU)
+#define CAN_BITRATE_UNKNOWN            0
+#define CAN_BITRATE_DEFAULT            500000
+
+/*
+ * CAN custom bit time
+ */
+enum can_bittimes {
+       CAN_BITTIME_STD,
+       CAN_BITTIME_BTR
+};
+
+/* TSEG1 of controllers usually is a sum of synch_seg (always 1),
+ * prop_seg and phase_seg1, TSEG2 = phase_seg2 */
+
+struct can_bittime_std {
+       __u32 brp;        /* baud rate prescaler */
+       __u8  prop_seg;   /* from 1 to 8 */
+       __u8  phase_seg1; /* from 1 to 8 */
+       __u8  phase_seg2; /* from 1 to 8 */
+       __u8  sjw:7;      /* from 1 to 4 */
+       __u8  sam:1;      /* 1 - enable triple sampling */
+};
+
+struct can_bittime_btr {
+       __u8  btr0;
+       __u8  btr1;
+};
+
+struct can_bittime {
+       enum can_bittimes type;
+       union {
+               struct can_bittime_std std;
+               struct can_bittime_btr btr;
+       };
+};
+
+/*
+ * CAN mode
+ */
+enum can_mode {
+       CAN_MODE_STOP = 0,
+       CAN_MODE_START,
+       CAN_MODE_SLEEP
+};
+
+/*
+ * CAN controller mode
+ */
+#define CAN_CTRLMODE_LOOPBACK   0x1
+#define CAN_CTRLMODE_LISTENONLY 0x2
+
+/*
+ * CAN operational and error states
+ */
+enum can_state {
+       CAN_STATE_ACTIVE = 0,
+       CAN_STATE_BUS_WARNING,
+       CAN_STATE_BUS_PASSIVE,
+       CAN_STATE_BUS_OFF,
+       CAN_STATE_STOPPED,
+       CAN_STATE_SLEEPING
+};
+
+/*
+ * CAN device statistics
+ */
+struct can_device_stats {
+       int error_warning;
+       int data_overrun;
+       int wakeup;
+       int bus_error;
+       int error_passive;
+       int arbitration_lost;
+       int restarts;
+       int bus_error_at_init;
+};
+
+#endif /* CAN_IOCTL_H */
diff --git a/kernel/2.6/include/socketcan/can/isotp.h b/kernel/2.6/include/socketcan/can/isotp.h
new file mode 100644 (file)
index 0000000..361dc30
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * socketcan/can/isotp.h
+ *
+ * Definitions for isotp CAN sockets
+ *
+ * $Id$
+ *
+ * Author: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ * Copyright (c) 2008 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_ISOTP_H
+#define CAN_ISOTP_H
+
+#include <socketcan/can.h>
+
+#define SOL_CAN_ISOTP (SOL_CAN_BASE + CAN_ISOTP)
+
+/* for socket options affecting the socket (not the global system) */
+
+#define CAN_ISOTP_OPTS         1
+#define CAN_ISOTP_RECV_FC      2
+
+struct can_isotp_options {
+
+       __u32 flags;            /* set flags for isotp behaviour.       */
+                               /* __u32 value : flags see below        */
+
+       __u32 frame_txtime;     /* frame transmission time (N_As/N_Ar)  */
+                               /* __u32 value : time in nano secs      */
+
+       __u8  ext_address;      /* set address for extended addressing  */
+                               /* __u8 value : extended address        */
+
+       __u8  txpad_content;    /* set content of padding byte (tx)     */
+                               /* __u8 value : content on tx path      */
+
+       __u8  rxpad_content;    /* set content of padding byte (rx)     */
+                               /* __u8 value : content on rx path      */
+};
+
+struct can_isotp_fc_options {
+
+       __u8  bs;               /* blocksize provided in FC frame       */
+                               /* __u8 value : blocksize. 0 = off      */
+
+       __u8  stmin;            /* separation time provided in FC frame */
+                               /* __u8 value :                         */
+                               /* 0x00 - 0x7F : 0 - 127 ms             */
+                               /* 0x80 - 0xF0 : reserved               */
+                               /* 0xF1 - 0xF9 : 100 us - 900 us        */
+                               /* 0xFA - 0xFF : reserved               */
+
+       __u8  wftmax;           /* max. number of wait frame transmiss. */
+                               /* __u8 value : 0 = omit FC N_PDU WT    */
+};
+
+
+/* flags for isotp behaviour */
+
+#define CAN_ISOTP_LISTEN_MODE  0x01    /* listen only (do not send FC) */
+#define CAN_ISOTP_EXTEND_ADDR  0x02    /* enable extended addressing */
+#define CAN_ISOTP_TX_PADDING   0x04    /* enable CAN frame padding tx path */
+#define CAN_ISOTP_RX_PADDING   0x08    /* enable CAN frame padding rx path */
+#define CAN_ISOTP_CHK_PAD_LEN  0x10    /* check received CAN frame padding */
+#define CAN_ISOTP_CHK_PAD_DATA 0x20    /* check received CAN frame padding */
+#define CAN_ISOTP_HALF_DUPLEX  0x40    /* half duplex error state handling */
+
+
+/* default values */
+
+#define CAN_ISOTP_DEFAULT_FLAGS                0
+#define CAN_ISOTP_DEFAULT_EXT_ADDRESS  0x00
+#define CAN_ISOTP_DEFAULT_RXPAD_CONTENT        0x00
+#define CAN_ISOTP_DEFAULT_TXPAD_CONTENT        0x00
+#define CAN_ISOTP_DEFAULT_FRAME_TXTIME 0
+#define CAN_ISOTP_DEFAULT_RECV_BS      0
+#define CAN_ISOTP_DEFAULT_RECV_STMIN   0x00
+#define CAN_ISOTP_DEFAULT_RECV_WFTMAX  0
+
+/*
+ * Remark on CAN_ISOTP_DEFAULT_RECV_* values:
+ *
+ * We can strongly assume, that the Linux Kernel implementation of
+ * CAN_ISOTP is capable to run with BS=0, STmin=0 and WFTmax=0.
+ * But as we like to be able to behave as a commonly available ECU,
+ * these default settings can be changed via sockopts.
+ * For that reason the STmin value is intentionally _not_ checked for
+ * consistency and copied directly into the flow control (FC) frame.
+ *
+ */
+
+#endif
diff --git a/kernel/2.6/include/socketcan/can/netlink.h b/kernel/2.6/include/socketcan/can/netlink.h
new file mode 100644 (file)
index 0000000..eccfb55
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * socketcan/can/netlink.h
+ *
+ * Definitions for the CAN netlink interface
+ *
+ * $Id: dev.h 939 2009-02-14 14:30:19Z wolf $
+ *
+ * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_NETLINK_H
+#define CAN_NETLINK_H
+
+#include <linux/types.h>
+
+/*
+ * CAN bit-timing parameters
+ *
+ * For futher information, please read chapter "8 BIT TIMING
+ * REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
+ * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
+ */
+struct can_bittiming {
+       __u32 bitrate;          /* Bit-rate in bits/second */
+       __u32 sample_point;     /* Sample point in one-tenth of a percent */
+       __u32 tq;               /* Time quanta (TQ) in nanoseconds */
+       __u32 prop_seg;         /* Propagation segment in TQs */
+       __u32 phase_seg1;       /* Phase buffer segment 1 in TQs */
+       __u32 phase_seg2;       /* Phase buffer segment 2 in TQs */
+       __u32 sjw;              /* Synchronisation jump width in TQs */
+       __u32 brp;              /* Bit-rate prescaler */
+};
+
+/*
+ * CAN harware-dependent bit-timing constant
+ *
+ * Used for calculating and checking bit-timing parameters
+ */
+struct can_bittiming_const {
+       char name[16];          /* Name of the CAN controller hardware */
+       __u32 tseg1_min;        /* Time segement 1 = prop_seg + phase_seg1 */
+       __u32 tseg1_max;
+       __u32 tseg2_min;        /* Time segement 2 = phase_seg2 */
+       __u32 tseg2_max;
+       __u32 sjw_max;          /* Synchronisation jump width */
+       __u32 brp_min;          /* Bit-rate prescaler */
+       __u32 brp_max;
+       __u32 brp_inc;
+};
+
+/*
+ * CAN clock parameters
+ */
+struct can_clock {
+       __u32 freq;             /* CAN system clock frequency in Hz */
+};
+
+/*
+ * CAN operational and error states
+ */
+enum can_state {
+       CAN_STATE_ERROR_ACTIVE = 0,     /* RX/TX error count < 96 */
+       CAN_STATE_ERROR_WARNING,        /* RX/TX error count < 128 */
+       CAN_STATE_ERROR_PASSIVE,        /* RX/TX error count < 256 */
+       CAN_STATE_BUS_OFF,              /* RX/TX error count >= 256 */
+       CAN_STATE_STOPPED,              /* Device is stopped */
+       CAN_STATE_SLEEPING,             /* Device is sleeping */
+       CAN_STATE_MAX
+};
+
+/*
+ * CAN controller mode
+ */
+struct can_ctrlmode {
+       __u32 mask;
+       __u32 flags;
+};
+
+#define CAN_CTRLMODE_LOOPBACK  0x1     /* Loopback mode */
+#define CAN_CTRLMODE_LISTENONLY        0x2     /* Listen-only mode */
+#define CAN_CTRLMODE_3_SAMPLES 0x4     /* Triple sampling mode */
+
+/*
+ * CAN device statistics
+ */
+struct can_device_stats {
+       __u32 bus_error;        /* Bus errors */
+       __u32 error_warning;    /* Changes to error warning state */
+       __u32 error_passive;    /* Changes to error passive state */
+       __u32 bus_off;          /* Changes to bus off state */
+       __u32 arbitration_lost; /* Arbitration lost errors */
+       __u32 restarts;         /* CAN controller re-starts */
+};
+
+/*
+ * CAN netlink interface
+ */
+enum {
+       IFLA_CAN_UNSPEC,
+       IFLA_CAN_BITTIMING,
+       IFLA_CAN_BITTIMING_CONST,
+       IFLA_CAN_CLOCK,
+       IFLA_CAN_STATE,
+       IFLA_CAN_CTRLMODE,
+       IFLA_CAN_RESTART_MS,
+       IFLA_CAN_RESTART,
+       __IFLA_CAN_MAX
+};
+
+#define IFLA_CAN_MAX   (__IFLA_CAN_MAX - 1)
+
+#endif /* CAN_NETLINK_H */
diff --git a/kernel/2.6/include/socketcan/can/platform/mcp251x.h b/kernel/2.6/include/socketcan/can/platform/mcp251x.h
new file mode 100644 (file)
index 0000000..d217ffa
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __CAN_PLATFORM_MCP251X_H__
+#define __CAN_PLATFORM_MCP251X_H__
+
+/*
+ *
+ * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ *
+ */
+
+/**
+ * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
+ * @oscillator_frequency:       - oscillator frequency in Hz
+ * @model:                      - actual type of chip
+ * @board_specific_setup:       - called before probing the chip (power,reset)
+ * @transceiver_enable:         - called to power on/off the transceiver
+ * @power_enable:               - called to power on/off the mcp *and* the
+ *                                transceiver
+ *
+ * Please note that you should define power_enable or transceiver_enable or
+ * none of them. Defining both of them is no use.
+ *
+ */
+
+struct mcp251x_platform_data {
+       unsigned long oscillator_frequency;
+       int model;
+#define CAN_MCP251X_MCP2510 0
+#define CAN_MCP251X_MCP2515 1
+       int (*board_specific_setup)(struct spi_device *spi);
+       int (*transceiver_enable)(int enable);
+       int (*power_enable) (int enable);
+};
+
+#endif /* __CAN_PLATFORM_MCP251X_H__ */
diff --git a/kernel/2.6/include/socketcan/can/platform/sja1000.h b/kernel/2.6/include/socketcan/can/platform/sja1000.h
new file mode 100644 (file)
index 0000000..01ee2ae
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _CAN_PLATFORM_SJA1000_H_
+#define _CAN_PLATFORM_SJA1000_H_
+
+/* clock divider register */
+#define CDR_CLKOUT_MASK 0x07
+#define CDR_CLK_OFF    0x08 /* Clock off (CLKOUT pin) */
+#define CDR_RXINPEN    0x20 /* TX1 output is RX irq output */
+#define CDR_CBP                0x40 /* CAN input comparator bypass */
+#define CDR_PELICAN    0x80 /* PeliCAN mode */
+
+/* output control register */
+#define OCR_MODE_BIPHASE  0x00
+#define OCR_MODE_TEST     0x01
+#define OCR_MODE_NORMAL   0x02
+#define OCR_MODE_CLOCK    0x03
+#define OCR_MODE_MASK     0x07
+#define OCR_TX0_INVERT    0x04
+#define OCR_TX0_PULLDOWN  0x08
+#define OCR_TX0_PULLUP    0x10
+#define OCR_TX0_PUSHPULL  0x18
+#define OCR_TX1_INVERT    0x20
+#define OCR_TX1_PULLDOWN  0x40
+#define OCR_TX1_PULLUP    0x80
+#define OCR_TX1_PUSHPULL  0xc0
+#define OCR_TX_MASK       0xfc
+#define OCR_TX_SHIFT      2
+
+struct sja1000_platform_data {
+       u32 clock;      /* CAN bus oscillator frequency in Hz */
+
+       u8 ocr;         /* output control register */
+       u8 cdr;         /* clock divider register */
+};
+
+#endif /* !_CAN_PLATFORM_SJA1000_H_ */
diff --git a/kernel/2.6/include/socketcan/can/raw.h b/kernel/2.6/include/socketcan/can/raw.h
new file mode 100644 (file)
index 0000000..d168cb5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * socketcan/can/raw.h
+ *
+ * Definitions for raw CAN sockets
+ *
+ * $Id$
+ *
+ * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
+ *          Urs Thuermann   <urs.thuermann@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_RAW_H
+#define CAN_RAW_H
+
+#include <socketcan/can.h>
+
+#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW)
+
+/* for socket options affecting the socket (not the global system) */
+
+enum {
+       CAN_RAW_FILTER = 1,     /* set 0 .. n can_filter(s)          */
+       CAN_RAW_ERR_FILTER,     /* set filter for error frames       */
+       CAN_RAW_LOOPBACK,       /* local loopback (default:on)       */
+       CAN_RAW_RECV_OWN_MSGS   /* receive my own msgs (default:off) */
+};
+
+#endif
diff --git a/kernel/2.6/include/socketcan/can/version.h b/kernel/2.6/include/socketcan/can/version.h
new file mode 100644 (file)
index 0000000..f7287f3
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * socketcan/can/version.h
+ *
+ * Version information for the CAN network layer implementation
+
+ * Author: Urs Thuermann   <urs.thuermann@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#ifndef CAN_VERSION_H
+#define CAN_VERSION_H
+
+#define RCSID(s) asm(".section .rodata.str1.1,\"aMS\",@progbits,1\n\t" \
+                    ".string \"" s "\"\n\t.previous\n")
+
+RCSID("$Id$");
+
+#endif /* CAN_VERSION_H */
index c21fd3603d055284dfec10967c24633a15d258cf..00de9efa1313c1ae611c89d4a9897bba6a23080d 100644 (file)
@@ -61,8 +61,8 @@
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/core.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
 #endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
 #endif
@@ -73,7 +73,7 @@
 #include "compat.h"
 #endif
 
 #include "compat.h"
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 static __initdata const char banner[] = KERN_INFO
 RCSID("$Id$");
 
 static __initdata const char banner[] = KERN_INFO
@@ -159,8 +159,8 @@ static int can_create(struct socket *sock, int protocol)
                return -EAFNOSUPPORT;
 #endif
 
                return -EAFNOSUPPORT;
 #endif
 
-#ifdef CONFIG_KMOD
-       /* try to load protocol module, when CONFIG_KMOD is defined */
+#ifdef CONFIG_MODULES
+       /* try to load protocol module kernel is modular */
        if (!proto_tab[protocol]) {
                err = request_module("can-proto-%d", protocol);
 
        if (!proto_tab[protocol]) {
                err = request_module("can-proto-%d", protocol);
 
@@ -930,7 +930,11 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
  */
 
 static struct packet_type can_packet __read_mostly = {
  */
 
 static struct packet_type can_packet __read_mostly = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+       .type = cpu_to_be16(ETH_P_CAN),
+#else
        .type = __constant_htons(ETH_P_CAN),
        .type = __constant_htons(ETH_P_CAN),
+#endif
        .dev  = NULL,
        .func = can_rcv,
 };
        .dev  = NULL,
        .func = can_rcv,
 };
@@ -1011,6 +1015,10 @@ static __exit void can_exit(void)
        }
        spin_unlock(&can_rcvlists_lock);
 
        }
        spin_unlock(&can_rcvlists_lock);
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
+#endif
+
        kmem_cache_destroy(rcv_cache);
 }
 
        kmem_cache_destroy(rcv_cache);
 }
 
index d1de572ee84b3c46d927499352ee511c0ae7b346..c639e0ebb9ef9ab4384542384c7c896916f1f33e 100644 (file)
@@ -48,7 +48,7 @@
 #include <linux/netdevice.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 #include <linux/netdevice.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
-#include <linux/can.h>
+#include <socketcan/can.h>
 
 /* af_can rx dispatcher structures */
 
 
 /* af_can rx dispatcher structures */
 
index 9d6385bbc1e6d1b73af783c545a2b9d6a13f85a7..4e47e9c268f0bdc4d2cd37e5524e48268aa1e395 100644 (file)
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/core.h>
-#include <linux/can/bcm.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/bcm.h>
 #include <net/sock.h>
 #include "compat.h"
 
 #include <net/sock.h>
 #include "compat.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 /* use of last_frames[index].can_dlc */
 RCSID("$Id$");
 
 /* use of last_frames[index].can_dlc */
index d525e69fad8316bd6d6e1a74f9459ebdf408aa5d..938d60be2cdcfa7a7607e2c4576830919686da20 100644 (file)
@@ -53,9 +53,9 @@
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/core.h>
-#include <linux/can/bcm.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/bcm.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
@@ -64,7 +64,7 @@
 #include "compat.h"
 #endif
 
 #include "compat.h"
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 /* use of last_frames[index].can_dlc */
 RCSID("$Id$");
 
 /* use of last_frames[index].can_dlc */
index 8f7260f12ef9d8df3642b18bcb9ae5c412caeed8..3cd7e56fdc18428a3a0fef5d2c7ddee650679408 100644 (file)
@@ -37,6 +37,17 @@ static inline void skb_set_timestamp(struct sk_buff *skb,
 }
 #endif
 
 }
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+static inline void setup_timer(struct timer_list * timer,
+                               void (*function)(unsigned long),
+                               unsigned long data)
+{
+       timer->function = function;
+       timer->data = data;
+       init_timer(timer);
+}
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
 #define round_jiffies(j) (j)
 #endif
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
 #define round_jiffies(j) (j)
 #endif
index f35a1c4dbedcce58cf80ed266539423142f5e777..22384fcb025022a2aa497676030012e9da91a89c 100644 (file)
@@ -61,9 +61,9 @@
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/core.h>
-#include <linux/can/isotp.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/isotp.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
@@ -72,7 +72,7 @@
 #include "compat.h"
 #endif
 
 #include "compat.h"
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 #define CAN_ISOTP_VERSION CAN_VERSION
 RCSID("$Id$");
 
 #define CAN_ISOTP_VERSION CAN_VERSION
index d0a6ac9d9d1c7e7e4c06deb7141bfafe7debeab1..f6f7c8213248258cbc6b9893f681b374caaf35a3 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 #include <linux/proc_fs.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
-#include <linux/can/core.h>
+#include <socketcan/can/core.h>
 
 #include "af_can.h"
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
 #include "compat.h"
 #endif
 
 
 #include "af_can.h"
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
 #include "compat.h"
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 /*
 RCSID("$Id$");
 
 /*
index f43706125e52cd1269c922bca01cc0c079b36b22..8df6364596e1d6b9e809fbb5a7a9b06ceb5c83ab 100644 (file)
@@ -50,9 +50,9 @@
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/core.h>
-#include <linux/can/raw.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/raw.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
@@ -61,7 +61,7 @@
 #include "compat.h"
 #endif
 
 #include "compat.h"
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 #define CAN_RAW_VERSION CAN_VERSION
 RCSID("$Id$");
 
 #define CAN_RAW_VERSION CAN_VERSION
index 87a60684c3a9b84d9afc1957edfcfdfa62db217b..9ff677a8e185aac03e113a19c1f2bd52c377ac74 100755 (executable)
--- a/strip-src
+++ b/strip-src
@@ -12,7 +12,7 @@
 #
 # Call the program as
 #
 #
 # Call the program as
 #
-#     strip-src [-v <version>] [-i] [-d] [<file>]
+#     strip-src [-v <version>] [-i] [-m] [-d] [<file>]
 #
 # The -v option will generate a source file for specified kernel version
 # where <version> is the kernel version you want the code to be generated
 #
 # The -v option will generate a source file for specified kernel version
 # where <version> is the kernel version you want the code to be generated
@@ -20,6 +20,8 @@
 #
 # The -i option will strip all Subversion Id lines from the the source.
 #
 #
 # The -i option will strip all Subversion Id lines from the the source.
 #
+# The -m option will replace macros like ND2D with real variable name.
+#
 # The -d (debug) option will give you some output on what the program does.
 #
 # If <file> is given, read that source file, otherwise stdin.
 # The -d (debug) option will give you some output on what the program does.
 #
 # If <file> is given, read that source file, otherwise stdin.
@@ -33,7 +35,7 @@ $re_if = "^\\#if LINUX_VERSION_CODE (==|!=|<|<=|>|>=) " .
 $re_elif = "^\\#elif LINUX_VERSION_CODE (==|!=|<|<=|>|>=) " .
     "KERNEL_VERSION\\((\\d+),(\\d+),(\\d+)\\)";
 
 $re_elif = "^\\#elif LINUX_VERSION_CODE (==|!=|<|<=|>|>=) " .
     "KERNEL_VERSION\\((\\d+),(\\d+),(\\d+)\\)";
 
-Getopts("div:");
+Getopts("dimv:");
 $debug = $opt_d;
 
 if (defined($opt_v)) {
 $debug = $opt_d;
 
 if (defined($opt_v)) {
@@ -45,6 +47,11 @@ unshift(@lines, "");
 
 if (defined($opt_v)) {
     strip_kversion($opt_v);
 
 if (defined($opt_v)) {
     strip_kversion($opt_v);
+    replace_socketcan($opt_v);
+
+    if (defined($opt_m)) {
+       replace_macros($opt_v);
+    }
 }
 
 if (defined($opt_i)) {
 }
 
 if (defined($opt_i)) {
@@ -55,9 +62,37 @@ for (@lines) {
     print if (defined($_));
 }
 
     print if (defined($_));
 }
 
+sub replace_socketcan {
+    my($i);
+
+    for $i (0..$#lines) {
+       $lines[$i] =~ s+socketcan/can+linux/can+g;
+    }
+}
+
+sub replace_macros {
+    my($version) = @_;
+    my($i);
+
+    $old = compare($version, "<", "2", "6", "21");
+
+    for $i (0..$#lines) {
+
+       if ($lines[$i] =~ /#define ND2D/) {
+           delete_line($i, "<del>");
+       } else {
+           if ($old) {
+               $lines[$i] =~ s/ND2D\(\b(\w+)\b\)/$1\->class_dev.dev/g;
+           } else {
+               $lines[$i] =~ s/ND2D\(\b(\w+)\b\)/$1\->dev.parent/g;
+           }
+       }
+    }
+}
+
 sub strip_id {
     my($i);
 sub strip_id {
     my($i);
-    
+
     for $i (0..$#lines) {
        
        if ($lines[$i] =~ /include.*linux(\/can)?\/version\.h/) {
     for $i (0..$#lines) {
        
        if ($lines[$i] =~ /include.*linux(\/can)?\/version\.h/) {