]> 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/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
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.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 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
 ------------------------
@@ -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:
-       ip link add type vcan
+       ip link add type vcan
 
   - 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':
-       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)
-  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)
-  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)
+  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
+export CONFIG_CAN_SLCAN=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_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_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
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
-       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---
@@ -46,6 +46,16 @@ config CAN_DEV
          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
@@ -60,18 +70,43 @@ config CAN_CALC_BITTIMING
          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---
-         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
@@ -85,19 +120,20 @@ config CAN_SJA1000_PLATFORM
 
 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
-         you should enable this option.
+         you may want to enable this option.
 
 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---
-         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"
@@ -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).
 
+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---
-         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
@@ -145,7 +188,7 @@ config CAN_KVASER_PCI
 
 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).
@@ -155,10 +198,24 @@ config CAN_SOFTING
        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
+       ---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)
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_CC770=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
-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/
@@ -47,6 +50,14 @@ obj-$(CONFIG_CAN_MSCAN_OLD)  += old/mscan/
 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
index 2cb7746e5969d64e38e7911d403536ccb78b5d88..fdf82fbaa4bd7e144f3f338878ecdb43a8847f2b 100644 (file)
@@ -26,9 +26,9 @@
 #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>
 
@@ -153,6 +153,19 @@ struct at91_priv {
        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)
 {
-       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)
 {
-       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;
 
-       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;
 
@@ -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:
  *
@@ -526,8 +534,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
                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.
                 */
@@ -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
-        * 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 ||
@@ -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))
-               new_state = CAN_STATE_BUS_PASSIVE;
+               new_state = CAN_STATE_ERROR_PASSIVE;
        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))
-               new_state = CAN_STATE_ACTIVE;
+               new_state = CAN_STATE_ERROR_ACTIVE;
        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) {
-       case CAN_STATE_ACTIVE:
+       case CAN_STATE_ERROR_ACTIVE:
                /*
                 * 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++;
-       case CAN_STATE_BUS_WARNING:     /* fallthrough */
+       case CAN_STATE_ERROR_WARNING:   /* fallthrough */
                /*
                 * 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;
@@ -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.
                 */
-               if (new_state <= CAN_STATE_BUS_PASSIVE)
+               if (new_state <= CAN_STATE_ERROR_PASSIVE)
                        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) {
-       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"
                 */
-       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;
-       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;
@@ -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) {
-               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;
 
-                       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;
@@ -829,32 +837,6 @@ static void at91_setup_mailboxes(struct net_device *dev)
        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);
@@ -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",
-                 reg_br, priv->can.bittiming.clock);
+                 reg_br, priv->can.clock.freq);
        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);
 
-       priv->can.state = CAN_STATE_ACTIVE;
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
        /* Enable interrupts */
        reg_ier =
@@ -933,8 +915,8 @@ static int at91_open(struct net_device *dev)
 
        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;
 
@@ -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;
-               goto out;
+               goto out_close;
        }
 
        /* start chip and queuing */
@@ -951,6 +933,8 @@ static int at91_open(struct net_device *dev)
 
        return 0;
 
+ out_close:
+       close_candev(dev);
  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);
 
-       can_close_cleanup(dev);
+       close_candev(dev);
 
        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;
@@ -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)
 {
@@ -1059,22 +1031,23 @@ static int __init at91_can_probe(struct platform_device *pdev)
                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->tx_timeout = at91_tx_timeout;
-       dev->get_stats          = at91_get_stats;
+#endif
        dev->irq                = irq;
-       dev->base_addr          = (unsigned long)addr;
        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.do_get_state          = at91_get_state;
        priv->can.do_set_mode           = at91_set_mode;
        priv->clk                       = clk;
+       priv->reg_base                  = addr;
 
        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;
 
@@ -1118,7 +1091,7 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
 
        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);
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) 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
  */
 
 #include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.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>
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+#error "CAN sysfs interface not support by this kernel version"
 #endif
-
 #include "sysfs.h"
+#endif
 
 #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
+ *
+ * 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)
@@ -63,10 +78,9 @@ static int can_update_spt(const struct can_bittiming_const *btc,
        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_bittiming *bt = &priv->bittiming;
        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) */
-               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;
-               rate = bt->clock / (brp * tsegall);
+               rate = priv->clock.freq / (brp * tsegall);
                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) {
-                       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 {
@@ -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;
-       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;
-
+#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 */
-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 */
 
+
+#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);
 }
+#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_bittiming *bt = &priv->bittiming;
        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;
+       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)
-               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;
@@ -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;
-       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;
 }
 
-/*
- * 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;
 
-       /* 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 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 */
-               if (!priv->bittiming.tq)
+               if (!bt->tq)
                        /* Determine bit-timing parameters */
-                       err = can_calc_bittiming(dev);
+                       err = can_calc_bittiming(dev, bt);
                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;
 }
-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
@@ -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.
  */
-
 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
- * 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);
 
-       /* 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;
@@ -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() ?? */
-               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);
        }
 }
@@ -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
- * 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)
 {
@@ -449,8 +369,9 @@ EXPORT_SYMBOL_GPL(can_free_echo_skb);
 /*
  * 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);
@@ -461,30 +382,20 @@ int can_restart_now(struct net_device *dev)
        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);
 
-       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));
-       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));
@@ -498,16 +409,35 @@ int can_restart_now(struct net_device *dev)
        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);
 
-       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);
+       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);
 
+#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.
  */
-void can_close_cleanup(struct net_device *dev)
+int open_candev(struct net_device *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);
 }
-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)
 {
-       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;
+#endif
 }
 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);
+
+#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/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/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"
 
@@ -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");
 
+#ifndef PCI_DEVICE_ID_PLX_9030
+# define PCI_DEVICE_ID_PLX_9030        0x9030
+#endif
 #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
@@ -434,7 +441,11 @@ static int esd331_create_err_frame(struct net_device *dev, canid_t idflags,
        if (unlikely(skb == NULL))
                return -ENOMEM;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+       stats = can_get_stats(dev);
+#else
        stats = &dev->stats;
+#endif
 
        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)
 {
+#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 *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)
-                       priv->can.state = CAN_STATE_ACTIVE;
+                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
                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_BUS_WARNING;
+                       priv->can.state = CAN_STATE_ERROR_WARNING;
 
                        /* 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)
 {
+       struct net_device *dev;
        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;
 
-               priv = netdev_priv(board->dev[msg.net]);
+               dev = board->dev[msg.net];
+               priv = netdev_priv(dev);
                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:
-                       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++;
-                       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++;
-                       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:
-                       esd331_handle_errmsg(board->dev[msg.net], &msg);
+                       esd331_handle_errmsg(dev, &msg);
                        break;
 
                default:
@@ -627,7 +647,6 @@ irqreturn_t esd331_interrupt(int irq, void *dev_id)
 
        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)
@@ -635,7 +654,7 @@ static int esd331_open(struct net_device *dev)
        struct esd331_priv *priv = netdev_priv(dev);
        int err;
 
-       err = can_set_bittiming(dev);
+       err = open_candev(dev);
        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);
 
-       priv->can.state = CAN_STATE_ACTIVE;
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
        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);
-       can_close_cleanup(dev);
+       close_candev(dev);
 
        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);
+#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;
        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:
-               priv->can.state = CAN_STATE_ACTIVE;
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
                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;
+       /* Set and enable PCI interrupts */
        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
 #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/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/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 */
-#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_RESET              0xC0
+#define INSTRUCTION_RESET      0xC0
 
 /* MPC251x registers */
 #define CANSTAT              0x0e
 #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 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). */
@@ -176,6 +179,7 @@ struct mcp251x_priv {
        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;
@@ -189,24 +193,41 @@ struct mcp251x_priv {
        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,
-               .len = 3,
+               .len = len,
                .cs_change = 0,
        };
        struct spi_message m;
-       u8 val = 0;
        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) {
@@ -219,27 +240,31 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
 
        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);
 
-       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);
-       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);
 
@@ -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;
 
-       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);
-
-       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);
-       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);
 
@@ -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;
 
-       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);
-
-       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;
 
-       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;
@@ -338,14 +327,6 @@ static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
                                          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);
@@ -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);
 
-               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);
-
-               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);
-       return 0;
 }
 
 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;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
        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;
@@ -444,36 +406,16 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
                                                          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;
+               int ret;
 
                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) {
-                       dev_dbg(&spi->dev, "%s: failed: ret = %d\n",
-                               __func__, ret);
                        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;
 
-       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)) {
-               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;
@@ -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);
-       struct spi_device *spi = priv->spi;
-
-       dev_dbg(&spi->dev, "%s (unimplemented)\n", __func__);
 
        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;
        }
@@ -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) {
-                       udelay(10);
+                       schedule();
                        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)
@@ -642,18 +586,18 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
        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 */
-       ret = can_set_bittiming(net);
-       if (ret)
+       ret = open_candev(net);
+       if (ret) {
                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),
@@ -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);
-
-       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)
@@ -682,7 +623,7 @@ static void mcp251x_hw_reset(struct spi_device *spi)
        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);
 }
@@ -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;
-
-       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;
+       priv->tx_len = 0;
        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);
 
@@ -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;
 
-       dev_dbg(&spi->dev, "%s\n", __func__);
-
        /* 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);
-       if (priv->tx_skb) {
+       if (priv->tx_skb || priv->tx_len) {
                net->stats.tx_errors++;
-               dev_kfree_skb(priv->tx_skb);
-               priv->tx_skb = NULL;
+               mcp251x_clean(priv);
        }
 
        mcp251x_hw_sleep(spi);
@@ -754,25 +696,8 @@ static int mcp251x_stop(struct net_device *net)
        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;
 }
@@ -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 net_device *net = priv->net;
        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);
+               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;
+       enum can_state new_state;
 
        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 */
-                       if (priv->tx_skb) {
+                       if (priv->tx_skb || priv->tx_len) {
                                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);
@@ -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;
-                       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);
-                       if (priv->tx_skb) {
+                       if (priv->tx_skb || priv->tx_len) {
                                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);
                }
 
@@ -849,27 +778,18 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                        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 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)) {
-                               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++;
-                                       dev_kfree_skb(priv->tx_skb);
-                                       priv->tx_skb = NULL;
+                                       mcp251x_clean(priv);
                                }
                                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);
 
-                       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 *)
@@ -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++;
@@ -929,21 +848,59 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
                                          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);
+               } 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 (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);
                }
 
@@ -956,8 +913,6 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
        }
 
        mcp251x_read_reg(spi, CANSTAT);
-
-       dev_dbg(&spi->dev, "interrupt ended\n");
 }
 
 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);
 
-       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);
@@ -973,15 +927,16 @@ static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
        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;
@@ -992,15 +947,19 @@ static struct net_device *alloc_mcp251x_netdev(int sizeof_priv)
 
        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->tx_timeout         = mcp251x_tx_timeout;
-       net->watchdog_timeo     = HZ;
+#endif
+       net->flags              |= IFF_ECHO;
 
        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.clock.freq      = pdata->oscillator_frequency / 2;
+       priv->can.do_set_bittiming      = mcp251x_do_set_bittiming;
 
        priv->net = net;
 
@@ -1020,7 +979,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        }
 
        /* 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;
@@ -1032,8 +991,6 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        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;
index 1f7dbfb1ef1b31f12bbe424b2e97c577b227b7cd..2f8fd1ef10f24e50b3aacda600bc74226da2958b 100644 (file)
@@ -19,6 +19,8 @@ obj-$(CONFIG_CAN_MPC52XX)     += mscan-mpc52xx.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
index 9279c9af0975333d147f5ee482fc99b6d0179425..6a3d608bc4ba9bb7846cc5658e88be1af74adce0 100644 (file)
@@ -24,8 +24,8 @@
 #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>
@@ -39,7 +39,7 @@
 
 #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$");
 
@@ -269,7 +269,11 @@ static unsigned int  __devinit mpc52xx_can_xtal_freq(struct device_node *np)
        unsigned int freq;
        u32 val;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
        freq = mpc52xx_find_ipb_freq(np);
+#else
+       freq = mpc5xxx_get_bus_frequency(np);
+#endif
        if (!freq)
                return 0;
 
@@ -317,8 +321,13 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct device_node *np,
 
        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);
+#else
+       if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
+               return mpc5xxx_get_bus_frequency(np);
+#endif
 
        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;
-       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;
@@ -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->base_addr, dev->irq, priv->bittiming.clock);
+                dev->base_addr, dev->irq, priv->clock.freq);
 
        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/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
@@ -38,7 +38,7 @@
 
 #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
@@ -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_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 = {
+       .name = "mscan",
        .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[] = {
-       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
 };
 
@@ -131,10 +132,10 @@ static int mscan_set_mode(struct net_device *dev, u8 mode)
        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->cantier, priv->tx_active);
+                       /* Suppress TX done interrupts */
+                       out_8(&regs->cantier, 0);
                }
 
                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
-                               priv->can.state = CAN_STATE_ACTIVE;
+                               priv->can.state = CAN_STATE_ERROR_ACTIVE;
                }
        }
        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;
-       if (state == CAN_STATE_BUS_OFF)
-               can_bus_off(dev);
        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++;
+                               stats->rx_errors++;
                        } else
                                frame->data[1] = 0;
 
                        if (check_set_state(dev, canrflg)) {
-                               frame->can_id |= CAN_ERR_CRTL;
                                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] |=
-                                                   CAN_ERR_CRTL_RX_WARNING;
+                                                       CAN_ERR_CRTL_RX_WARNING;
 
                                        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;
-                               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] |=
-                                           CAN_ERR_CRTL_RX_PASSIVE;
+                                               CAN_ERR_CRTL_RX_PASSIVE;
                                        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;
@@ -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;
 
-       /* 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
-       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);
@@ -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);
 
+       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);
-       free_irq(dev->irq, dev);
        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;
index 0a05a0bf7cb996c0b53fa16e7bf0da1d4fe05e4e..f3524667116a2725121e5d914ba50797fecbb7db 100644 (file)
@@ -239,7 +239,8 @@ struct mscan_platform_data {
 #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.
  */
index 8c44d9fea32020d21ca8e89d7e60028168af983f..507e28dbf2d69057bf1512341ec6872c65ac4a44 100644 (file)
@@ -15,7 +15,7 @@ else
 
 -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
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/can.h>
+#include <socketcan/can.h>
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
@@ -44,8 +44,8 @@
 #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)
index b7a5460195e136e9dbf69957010753647599e970..dfba87517011c833be0a0cb9dc9a6d3c3c4225f3 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef __CCAN_H__
 #define __CCAN_H__
 
-#include <linux/can.h>
+#include <socketcan/can.h>
 #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/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
index 16d585ecdfc074f831a75b1a50bb5a55dee3a040..6372aa621d53b9602cd724e89fcf6aee5fc97fbb 100644 (file)
 #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 <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>");
@@ -1055,23 +1055,20 @@ static int can_close(struct net_device *dev)
        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 */
 
-       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);
@@ -1081,14 +1078,19 @@ void can_netdev_setup(struct net_device *dev)
        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->tx_timeout                 = can_tx_timeout;
+#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;
 }
 
index 6028e96138359de40a4bf8e287a270a8f5231706..e1b02aa2cefdb0d1594a54c4982f3df3685d73e1 100644 (file)
 #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 <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[];
@@ -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);
+#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);
+#endif
                                /* 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/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 <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h>     /* for RCSID. Removed by mkpatch script */
 
 RCSID("$Id$");
 
index 2d6e13d36ea60e0c6368395be3dafe634a24a4fc..4329aeb6b09d975f52cdec5e841c756ff99e69a4 100644 (file)
 #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/can/dev.h>
-#include <linux/can/error.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.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
index 86a81e8bb1a2416a55f6f66291ad19dfa0a0e700..562133fdcc4d0d4cc4f6fc6b2f048df526772db5 100644 (file)
 #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 <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[];
@@ -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);
+#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);
+#endif
                                /* count number of restarts */
                                priv->can_stats.restarts++;
 
index c8876f36784bf8c41532111d89fdbc81031ecd89..97c8f0001e1a98d127db1fac083a67b4a3b0daf6 100644 (file)
 #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 <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>");
@@ -1007,23 +1007,20 @@ static void test_if(struct net_device *dev)
 }
 #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 */
 
-       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);
@@ -1041,14 +1038,19 @@ void can_netdev_setup(struct net_device *dev)
 
        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->tx_timeout                 = can_tx_timeout;
+#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;
 }
 
index d88d51ea8046c20d32fcc4fd63d94b06fac3d72d..5fd822a2c8fd2c22f268d6c0d0d58018b110c56a 100644 (file)
@@ -14,19 +14,22 @@ modules modules_install clean:
 else
 
 -include $(TOPDIR)/Makefile.common
-#EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/can/hal
 
 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_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
 
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+ifeq ($(CONFIG_CAN_DEBUG_DEVICES),y)
+       EXTRA_CFLAGS += -DDEBUG
+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/version.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
 
 #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");
 
-#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 {
+       int version;
        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 */
 
+/*
+ * 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.
- * 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)
 
@@ -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)
-#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_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[] = {
-       {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);
@@ -101,49 +123,64 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
 /*
  * 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 */
-       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
  */
-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 */
-       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 */
-       res = ems_pci_read_reg(dev, REG_CDR);
+       res = priv->read_reg(priv, REG_CDR);
 
        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;
+       int max_chan, mem_size, base_bar;
        int err, i;
 
        /* Enabling PCI device */
@@ -218,40 +256,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
 
        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;
-
                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;
-
                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 */
-       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;
@@ -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;
+#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->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 */
-               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);
 
-                       /* 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);
@@ -292,9 +358,8 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
 
                        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);
                }
index 0f6219df9efd8ebc61d2b55373d3ef473e0f4ac4..75fcab46fe3f0359c9f9573253fdfe51eaf06058 100644 (file)
  */
 
 #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/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>
 
 #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");
@@ -94,14 +99,15 @@ MODULE_DEVICE_TABLE (pcmcia, ems_pcmcia_tbl);
 
 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)
@@ -116,6 +122,10 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
        irqreturn_t retval = IRQ_NONE;
        int i, again;
 
+       /* Card not present */
+       if (readw(card->base_addr) != 0xAA55)
+               return IRQ_HANDLED;
+
        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
  */
-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 */
-       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 */
-       res = ems_pcmcia_read_reg(dev, REG_CDR);
+       res = ems_pcmcia_read_reg(priv, REG_CDR);
 
        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);
 
+#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->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 */
-               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->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;
@@ -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 "
-                              "#%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);
                }
@@ -347,7 +362,7 @@ static int __devinit ems_pcmcia_probe(struct pcmcia_device *dev)
 /*
  * 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;
index c962029e767398cc36bdb2c2665f35ff1c051d46..8881b1aa57c5310daa18a5a4e3ab26c960195732 100644 (file)
  */
 
 #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/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
 
 #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");
@@ -112,14 +117,14 @@ static struct pci_device_id 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)
@@ -144,21 +149,26 @@ static struct net_device * __devinit esd_pci_add_chan(struct pci_dev *pdev,
 
        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->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 */
+#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;
 
-       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);
 
index 9f84b4b66c07dc1e0e375a4ca23fa86fa1251813..a86d643dc7e6913414bfa680c9f6d9ced6668c2a 100644 (file)
  */
 
 #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/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
@@ -80,16 +81,25 @@ static struct pci_device_id 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)
@@ -114,21 +124,25 @@ static struct net_device *ixxat_pci_add_chan(struct pci_dev *pdev,
 
        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->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;
 
-       /* 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;
 
-       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);
 
index fb10907ceaacc85b633e387f79c190b33fb305ca..966f109ac24914778820b2ba50dabfdcaac6e680 100644 (file)
  */
 
 #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/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
@@ -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");
 
-#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;
@@ -122,38 +122,39 @@ static struct pci_device_id 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;
-       u32 tmp;
+       u32 intcsr;
 
        /* 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;
-       u32 tmp;
+       u32 tmp_en_io;
 
        /* 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)
@@ -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);
-               udelay(10);
                /* 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 (!priv)
-               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);
 
+       /* 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",
@@ -204,10 +205,7 @@ static void kvaser_pci_del_chan(struct net_device *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);
 
@@ -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,
-                              unsigned long base_addr)
+                              void __iomem *base_addr)
 {
        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;
 
-       /*S5920*/
+       /* S5920 */
        board->conf_addr = conf_addr;
 
-       /*XILINX board wide address*/
+       /* XILINX board wide address */
        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);
 
-               /* Disable interrupts from card */
-               kvaser_pci_disable_irq(dev);
                /* 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;
        }
 
-       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->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;
 
-       /* 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;
+
        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);
 
@@ -323,14 +324,14 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
        if (err)
                goto failure_release_pci;
 
-       /*S5920*/
+       /* S5920 */
        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;
@@ -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,
-                                         (unsigned long)base_addr);
+                                         base_addr);
                if (err)
                        goto failure_cleanup;
        }
@@ -370,13 +371,14 @@ failure_cleanup:
        kvaser_pci_del_chan(master_dev);
 
 failure_iounmap:
-       if (conf_addr == NULL)
+       if (conf_addr != NULL)
                pci_iounmap(pdev, conf_addr);
-       if (res_addr == NULL)
+       if (res_addr != NULL)
                pci_iounmap(pdev, res_addr);
-       if (base_addr == NULL)
+       if (base_addr != NULL)
                pci_iounmap(pdev, base_addr);
 
+failure_release_regions:
        pci_release_regions(pdev);
 
 failure_release_pci:
index 22d69e459dfb66f3ee0f9d351a7507a6fc481ce7..9decb90ba86881e41e437ae6af4a73e9b041b46c 100644 (file)
  */
 
 #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/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
 
 #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");
@@ -81,23 +86,19 @@ static struct pci_device_id 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;
 
@@ -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:
-               iounmap((void *)dev->base_addr);
+               iounmap(priv->reg_base);
        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;
 
-       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;
        }
@@ -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->can.bittiming.clock = PEAK_PCI_CAN_CLOCK;
+       priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
 
        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;
 
-       /* 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)
@@ -249,8 +255,8 @@ static int peak_pci_add_chan(struct pci_dev *pdev, int channel,
        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;
 
index b7414b2186974d6b4ba3c41a6edcf7f5b6dc49e7..325a8238ed08c9a0a40c25a46ee4b0e293b7877a 100644 (file)
  */
 
 #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/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"
 
+#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");
@@ -44,14 +49,14 @@ MODULE_LICENSE("GPL v2");
 #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)
@@ -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->can.bittiming.clock = PIPCAN_CAN_CLOCK;
+       priv->can.clock.freq = PIPCAN_CAN_CLOCK;
        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;
+       priv->reg_base = (void __iomem *)res->start;
 
        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/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 <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");
-MODULE_DESCRIPTION(DRV_NAME " CAN netdevice driver");
+MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver");
 
 static struct can_bittiming_const sja1000_bittiming_const = {
+       .name = DRV_NAME,
        .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);
 
-       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 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);
-       unsigned char status = priv->read_reg(dev, REG_MOD);
+       unsigned char status = priv->read_reg(priv, REG_MOD);
        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;
-                       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);
+               status = priv->read_reg(priv, REG_MOD);
        }
 
        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);
-       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) {
-                       priv->can.state = CAN_STATE_ACTIVE;
+                       priv->can.state = CAN_STATE_ERROR_ACTIVE;
                        /* 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 */
-               priv->write_reg(dev, REG_MOD, 0x00);
-               status = priv->read_reg(dev, REG_MOD);
+               priv->write_reg(priv, REG_MOD, 0x00);
                udelay(10);
+               status = priv->read_reg(priv, REG_MOD);
        }
 
        dev_err(ND2D(dev), "setting SJA1000 into normal mode failed!\n");
-       return 1;
-
 }
 
 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 */
-       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);
@@ -174,11 +170,11 @@ static int sja1000_set_mode(struct net_device *dev, enum can_mode mode)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
+       if (!priv->open_time)
+               return -EINVAL;
+
        switch (mode) {
        case CAN_MODE_START:
-               if (!priv->open_time)
-                       return -EINVAL;
-
                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;
 }
 
-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);
@@ -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) |
-               (((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;
 }
@@ -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 */
-       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) */
-       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;
-               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;
-               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++)
-               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);
 
-       priv->write_reg(dev, REG_CMR, CMD_TR);
+       priv->write_reg(priv, REG_CMR, CMD_TR);
 
        return 0;
 }
@@ -355,22 +316,22 @@ static void sja1000_rx(struct net_device *dev)
        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;
-               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 = (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)
@@ -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->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 */
-       priv->write_reg(dev, REG_CMR, CMD_RRB);
+       priv->write_reg(priv, REG_CMR, CMD_RRB);
 
        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;
-               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 */
-               priv->can.can_stats.error_warning++;
                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) {
-                       state = CAN_STATE_BUS_WARNING;
+                       state = CAN_STATE_ERROR_WARNING;
                } else
-                       state = CAN_STATE_ACTIVE;
+                       state = CAN_STATE_ERROR_ACTIVE;
        }
        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;
 
@@ -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");
-               priv->can.can_stats.error_passive++;
                if (status & SR_ES)
-                       state = CAN_STATE_BUS_PASSIVE;
+                       state = CAN_STATE_ERROR_PASSIVE;
                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");
-               alc = priv->read_reg(dev, REG_ALC);
+               alc = priv->read_reg(priv, REG_ALC);
                priv->can.can_stats.arbitration_lost++;
+               stats->rx_errors++;
                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;
-               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;
-               else
+               } else {
+                       priv->can.can_stats.error_passive++;
                        cf->data[1] = (txerr > rxerr) ?
                                CAN_ERR_CRTL_TX_PASSIVE :
                                CAN_ERR_CRTL_RX_PASSIVE;
+               }
        }
 
        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? */
-       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)
-               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++;
-               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++;
@@ -553,7 +518,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
                        /* 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)) {
@@ -564,7 +529,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
        }
 
        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);
@@ -581,22 +546,19 @@ static int sja1000_open(struct net_device *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 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);
-#endif
-               if (err)
+               if (err) {
+                       close_candev(dev);
                        return -EAGAIN;
+               }
        }
 
 #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);
 
-       set_reset_mode(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);
 
+       close_candev(dev);
+
+       priv->open_time = 0;
+
        return 0;
 }
 
@@ -638,7 +602,11 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
                return NULL;
 
        priv = netdev_priv(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);
@@ -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 = {
-       .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)
 {
-       struct sja1000_priv *priv = netdev_priv(dev);
-       int err;
-
        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
@@ -679,23 +642,12 @@ int register_sja1000dev(struct net_device *dev)
        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);
-       return 0;
+
+       return register_candev(dev);
 }
 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,
@@ -49,9 +47,8 @@
 #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 */
 
  * 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;
 
-       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;
 
-       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);
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 {
- *           compatible = "philips,sja1000";
+ *           compatible = "nxp,sja1000";
  *           reg = <3 0x100 0x80>;
- *           clock-frequency = <8000000>;
- *           cdr-reg = <0x48>;
- *           ocr-reg = <0x0a>;
  *           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/version.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>
@@ -56,19 +58,21 @@ MODULE_LICENSE("GPL v2");
 #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);
+       struct sja1000_priv *priv = netdev_priv(dev);
        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);
-       iounmap((void __iomem *)dev->base_addr);
+       iounmap(priv->reg_base);
        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;
 }
@@ -102,18 +106,20 @@ static int __devinit sja1000_ofp_probe(struct of_device *ofdev,
                return err;
        }
 
-       res_size = res.end - res.start + 1;
+       res_size = resource_size(&res);
 
        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) {
-               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;
        }
@@ -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;
 
+       /* backward compatibility */
        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)))
-               priv->can.bittiming.clock = *prop;
+               priv->can.clock.freq = *prop / 2;
        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);
-       if (prop && (prop_size == sizeof(u32)))
+       if (prop && (prop_size == sizeof(u32))) {
                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);
-       if (prop && (prop_size == sizeof(u32)))
+       if (prop && (prop_size == sizeof(u32))) {
                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,
-                "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);
index a6c5d760895f231daa5650960d40e0ea0b6ff1b4..d1bfaecd6a7818e690b48663b951bdf109d02834 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/version.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/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"
 
+#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");
 
-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)
 {
-       int err, irq;
+       int err;
        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;
        }
 
-       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;
        }
 
-       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;
        }
 
-       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;
@@ -95,15 +94,15 @@ static int sp_probe(struct platform_device *pdev)
        }
        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->can.bittiming.clock = pdata->clock;
+       priv->can.clock.freq = pdata->clock;
        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);
 
@@ -114,8 +113,8 @@ static int sp_probe(struct platform_device *pdev)
                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:
@@ -123,7 +122,7 @@ static int sp_probe(struct platform_device *pdev)
  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;
 }
@@ -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);
+       struct sja1000_priv *priv = netdev_priv(dev);
        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);
 
index 1f6c67724cf6b0c60edcc6a9825b50955ab57a2c..b29a0deae648ee9545063f1c81bbb1f393afa72b 100644 (file)
@@ -73,9 +73,9 @@
 #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[] =
@@ -528,16 +528,31 @@ static int slc_open(struct net_device *dev)
        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)
 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops = &slc_netdev_ops;
+#else
        dev->open               = slc_open;
-       dev->destructor         = free_netdev;
        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
-       dev->hard_start_xmit    = slc_xmit;
 
        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
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
        dev->tx_timeout         = slc_tx_timeout;
+#endif
        dev->watchdog_timeo     = 20*HZ;
 #endif
 
index df3fceca7bd014694a7fbe9b4511b80ecaeeb188..d65a5e9878e1a3ab6e9dc94d35e6e7aa7928eb2f 100644 (file)
@@ -13,7 +13,7 @@ else
 
 -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
 
index e43c7f11679991c65291d63f42e0755aa9e6cac6..20da9189e8cfd84de4a18db02af97f8c76d1ab3a 100644 (file)
@@ -6,8 +6,9 @@
 
 #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;
@@ -64,10 +65,13 @@ struct softing {
        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;
+               int failed; /* firmware has failed */
                /* 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;
-               u16  chip [2];
+               u16  chip[2];
                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 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);
@@ -155,11 +159,20 @@ extern int softing_reset_chip(struct softing *card);
  */
 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 {
@@ -244,25 +257,3 @@ struct softing_info {
 /* 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/version.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)
-               mod_alert("failed %u", ret);
+               dev_alert(&pcmcia->dev, "failed %u\n", 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) {
-                       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) {
-                       mod_alert("%s: cf->Vcc mismatch\n", __FILE__);
+                       dev_alert(&pdev->dev, "cf->Vcc mismatch\n");
                        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) {
-                       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 */
@@ -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)) {
-                       mod_alert("pcmcia_map_mem_page() mismatch\n");
+                       dev_alert(&pdev->dev,
+                               "pcmcia_map_mem_page() mismatch\n");
                        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;
@@ -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);
-       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);
@@ -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;
-       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);
@@ -334,35 +341,37 @@ static int __devinit driver_probe(struct pcmcia_device *pcmcia)
        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 */
-       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)
-               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) {
-               printk(", irq %d", pcmcia->irq.AssignedIRQ);
+               str += sprintf(str, ", irq %d", pcmcia->irq.AssignedIRQ);
                card->irq.nr = pcmcia->irq.AssignedIRQ;
        }
+
        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);
-                       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;
@@ -407,13 +416,11 @@ static struct pcmcia_driver softing_cs_driver = {
 
 static int __init mod_start(void)
 {
-       mod_trace("");
        return pcmcia_register_driver(&softing_cs_driver);
 }
 
 static void __exit mod_stop(void)
 {
-       mod_trace("");
        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)
-                               mod_alert("%s returned %u", msg, ret);
+                               dev_alert(card->dev,
+                                       "%s returned %u\n", msg, ret);
                        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) {
-               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 {
-               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;
        }
@@ -219,16 +222,18 @@ int softing_bootloader_command(struct softing *card
 
        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:
-               mod_alert("%s: response from card nok", msg);
+               dev_alert(card->dev, "%s: response from card nok\n", msg);
                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:
-               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;
@@ -273,16 +278,18 @@ int softing_load_fw(const char *file, struct softing *card,
        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) {
-               mod_alert("request_firmware(%s) got %i", file, ret);
+               dev_alert(card->dev, "request_firmware(%s) got %i\n",
+                       file, 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];
@@ -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) {
-               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)) {
-               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;
@@ -313,13 +322,15 @@ int softing_load_fw(const char *file, struct softing *card,
                        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) {
-                       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],
@@ -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)) {
-                       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 */
@@ -336,8 +348,8 @@ int softing_load_fw(const char *file, struct softing *card,
                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:
@@ -346,7 +358,7 @@ fw_end:
                /*got eof & start */
                return 0;
        }
-       mod_alert("failed");
+       dev_info(card->dev, "firmware %s failed\n", file);
        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];
+       struct cmd {
+               u32 start;
+               u8 autorestart;
+       } __attribute__((packed)) *pcmdstart =
+               (struct cmd *)&card->dpram.command[1];
 
        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;
        }
-       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];
@@ -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) {
-               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)) {
-               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;
@@ -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) {
-                       mod_alert("unknown record type 0x%04x", rec.type);
+                       dev_alert(card->dev, "unknown record type 0x%04x\n",
+                               rec.type);
                        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)) {
-                       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);
-       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)
 {
-       mod_trace("%s", card->id.name);
        do {
                /*reset chip */
                card->dpram.info->reset_rcv_fifo = 0;
@@ -476,58 +492,77 @@ failed:
        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 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 (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;
+       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->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->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 */
@@ -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 */
-               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 (bus1) {
+       if (mask_start & 2) {
+               pbus = card->bus[1];
                /*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->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->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 */
@@ -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 */
-               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;
        }
-       /*set interrupt */
        /*enable_error_frame */
+       /*
        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;
@@ -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;
-       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();
        }
+
+       card->boot_time = ktime_get_real();
+
        /*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;
 
-       /*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:
+       dev_alert(card->dev, "firmware failed, going idle\n");
        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;
 }
 
@@ -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:
-               return raw * 4 / 5;
+               ovf = ovf * 4 / 5;
+               rawl = rawl * 4 / 5;
+               break;
        case 24:
-               return raw * 2 / 3;
+               ovf = ovf * 2 / 3;
+               rawl = rawl * 2 / 3;
+               break;
        case 25:
-               return raw * 16 / 25;
+               ovf = ovf * 16 / 25;
+               rawl = rawl * 16 / 25;
+               break;
        case 0:
        case 16:
+               break;
        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
 */
 
+#include <linux/version.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"
 
-/* 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)
 {
-       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;
@@ -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;
 
-       ret = -ENOTTY;
        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);
        }
-       if (!card->fw.up) {
-               ret = -EIO;
+       ret = NETDEV_TX_BUSY;
+       if (!card->fw.up)
                goto xmit_done;
-       }
-       if (netif_carrier_ok(priv->netdev) <= 0) {
-               ret = -EBADF;
+       if (card->tx.pending >= TXMAX)
                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;
-       }
        fifo_wr = card->dpram.tx->wr;
-       if (fifo_wr == card->dpram.tx->rd) {
+       if (fifo_wr == card->dpram.tx->rd)
                /*fifo full */
-               ret = -EAGAIN;
                goto xmit_done;
-       }
        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;
-       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;
-       /* 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);
@@ -138,10 +126,36 @@ xmit_done:
                        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;
 }
 
@@ -149,12 +163,15 @@ static int softing_dev_svc_once(struct softing *card)
 {
        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;
+       u8 *ptr;
+       u32 tmp;
+       u8 cmd;
 
        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;
-               /*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;
-                       if (!netif_carrier_ok(bus->netdev))
+                       if (!canif_is_active(bus->netdev))
+                               /* a dead bus has no overflows */
                                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;
-       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;
-       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)
-               stats = can_get_stats(bus->netdev);
+       stats = can_get_stats(bus->netdev);
 #else
-               stats = &bus->netdev->stats;
+       stats = &bus->netdev->stats;
 #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() */
-                               softing_flush_echo_skb(bus);
                                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;
-                       /*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;
 }
 
@@ -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_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;
-               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
@@ -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) {
-               card_seems_down(card);
+               dev_alert(card->dev, "I think the card is gone\n");
                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();
-       mod_trace("0x%02x", irq_host);
        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);
@@ -425,78 +410,45 @@ static int netdev_open(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);
-       /* determine and set bittime */
-       ret = can_set_bittiming(ndev);
+       /* check or determine and set bittime */
+       ret = open_candev(ndev);
        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;
+failed:
+       return ret;
 }
 
 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_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;
-       mod_trace("%s %u", ndev->name, mode);
+       int ret;
+
        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;
@@ -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) {
-                       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;
@@ -538,7 +489,7 @@ int softing_card_irq(struct softing *card, int enable)
 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;
@@ -560,7 +511,12 @@ static void shutdown_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) {
@@ -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->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;
        }
+       wmb();
        /*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];
 
-       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]);
 
@@ -673,191 +612,13 @@ open_failed:
        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)
 {
@@ -866,7 +627,7 @@ static struct softing_priv *mk_netdev(struct softing *card, u16 chip_id)
 
        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);
@@ -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->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;
+#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;
-       priv->can.do_get_state  = candev_get_state;
+#endif
        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;
-       netif_carrier_off(priv->netdev);
        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;
        }
-       ret = mk_netdev_sysfs(priv);
+       ret = softing_bus_sysfs_create(priv);
        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;
@@ -917,12 +677,6 @@ reg_failed:
        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;
@@ -931,11 +685,15 @@ void rm_softing(struct softing *card)
        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);
 }
@@ -952,16 +710,15 @@ int mk_softing(struct softing *card)
 
        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;
-       mod_trace("can (%s)", card->id.name);
 
        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;
        }
 
@@ -980,51 +737,56 @@ int mk_softing(struct softing *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;
 
-       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]);
-               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]) {
-                       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])) {
-                       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;
                }
        }
-       mod_trace("card initialised");
+       dev_info(card->dev, "card initialised\n");
        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) {
-               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:
@@ -1040,13 +802,13 @@ EXPORT_SYMBOL(mk_softing);
 
 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)
 {
-       mod_trace("");
+       printk(KERN_INFO "[%s] stop\n", THIS_MODULE->name);
 }
 
 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/version.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"
 
@@ -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);
-       int err = 0;
 
        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,
@@ -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->state != CAN_STATE_STOPPED)
+               return -EBUSY;
        priv->restart_ms = ms;
        return 0;
 }
@@ -369,16 +367,20 @@ out:
        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,                           \
@@ -450,8 +452,8 @@ static ssize_t can_stat_show(const struct device *d,
 
        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;
@@ -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(bus_off);
 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,
+       &dev_attr_bus_off.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
 };
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);
+int can_sample_point(struct can_bittiming *bt);
 
 #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/can.h>
+#include <socketcan/can.h>
 #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[] =
index 5121cd634704749d8b6b3312606285292864f635..fbe374129cabc406bed2949ec08eb65b140e244b 100644 (file)
 #define CAN_DEV_H
 
 #include <linux/version.h>
+#include <linux/can/netlink.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
  */
@@ -54,39 +29,6 @@ enum can_mode {
        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
  */
@@ -100,22 +42,20 @@ struct can_priv {
 
        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;
-       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);
-       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_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)
@@ -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);
+
+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_set_bittiming(struct net_device *dev);
-
 int can_restart_now(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);
 
-int can_sample_point(struct can_bittiming *bt);
-
 #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_MASK     0x07
 #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_TX_MASK       0xfc
+#define OCR_TX_SHIFT      2
 
 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/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
@@ -73,7 +73,7 @@
 #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
@@ -159,8 +159,8 @@ static int can_create(struct socket *sock, int protocol)
                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);
 
@@ -930,7 +930,11 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
  */
 
 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),
+#endif
        .dev  = NULL,
        .func = can_rcv,
 };
@@ -1011,6 +1015,10 @@ static __exit void can_exit(void)
        }
        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);
 }
 
index d1de572ee84b3c46d927499352ee511c0ae7b346..c639e0ebb9ef9ab4384542384c7c896916f1f33e 100644 (file)
@@ -48,7 +48,7 @@
 #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 */
 
index 9d6385bbc1e6d1b73af783c545a2b9d6a13f85a7..4e47e9c268f0bdc4d2cd37e5524e48268aa1e395 100644 (file)
 #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 <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 */
index d525e69fad8316bd6d6e1a74f9459ebdf408aa5d..938d60be2cdcfa7a7607e2c4576830919686da20 100644 (file)
@@ -53,9 +53,9 @@
 #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>
@@ -64,7 +64,7 @@
 #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 */
index 8f7260f12ef9d8df3642b18bcb9ae5c412caeed8..3cd7e56fdc18428a3a0fef5d2c7ddee650679408 100644 (file)
@@ -37,6 +37,17 @@ static inline void skb_set_timestamp(struct sk_buff *skb,
 }
 #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
index f35a1c4dbedcce58cf80ed266539423142f5e777..22384fcb025022a2aa497676030012e9da91a89c 100644 (file)
@@ -61,9 +61,9 @@
 #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>
@@ -72,7 +72,7 @@
 #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
index d0a6ac9d9d1c7e7e4c06deb7141bfafe7debeab1..f6f7c8213248258cbc6b9893f681b374caaf35a3 100644 (file)
 #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 <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 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/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>
@@ -61,7 +61,7 @@
 #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
index 87a60684c3a9b84d9afc1957edfcfdfa62db217b..9ff677a8e185aac03e113a19c1f2bd52c377ac74 100755 (executable)
--- a/strip-src
+++ b/strip-src
@@ -12,7 +12,7 @@
 #
 # 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
@@ -20,6 +20,8 @@
 #
 # 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.
@@ -33,7 +35,7 @@ $re_if = "^\\#if LINUX_VERSION_CODE (==|!=|<|<=|>|>=) " .
 $re_elif = "^\\#elif LINUX_VERSION_CODE (==|!=|<|<=|>|>=) " .
     "KERNEL_VERSION\\((\\d+),(\\d+),(\\d+)\\)";
 
-Getopts("div:");
+Getopts("dimv:");
 $debug = $opt_d;
 
 if (defined($opt_v)) {
@@ -45,6 +47,11 @@ unshift(@lines, "");
 
 if (defined($opt_v)) {
     strip_kversion($opt_v);
+    replace_socketcan($opt_v);
+
+    if (defined($opt_m)) {
+       replace_macros($opt_v);
+    }
 }
 
 if (defined($opt_i)) {
@@ -55,9 +62,37 @@ for (@lines) {
     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);
-    
+
     for $i (0..$#lines) {
        
        if ($lines[$i] =~ /include.*linux(\/can)?\/version\.h/) {