-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Oliver,

like I've written on netdev I'm posting the ems_usb driver here.

At the moment I'm fighting with the netlink interface. Everytime I want
to set the bitrate I'm getting the following error from the IP tool:

sudo ./ip link set can0 type can bitrate 500000
RTNETLINK answers: Numerical argument out of domain

dmesg says:
[ 1185.018724] ems_usb 2-6:1.0: bitrate error 100.0% too high

Any ideas? I hope I'm using the candev interface correctly.

- --
Mit freundlichen Gruessen/Best Regards,

Sebastian Haas
Software Entwicklung/Software Development

Phone: +49-9451-9432-22
Fax  : +49-9451-9432-12
Email: [email protected]
Web  : www.ems-wuensche.com


Index: include/linux/cpc.h
===================================================================
- --- include/linux/cpc.h       (Revision 0)
+++ include/linux/cpc.h (Revision 0)
@@ -0,0 +1,440 @@
+/*
+ * CPC CAN Interface Definitions
+ *
+ * Copyright (C) 2000-2008 EMS Dr. Thomas Wuensche
+ *
+ * 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.
+ */
+#ifndef CPC_HEADER
+#define CPC_HEADER
+
+// the maximum length of the union members within a CPC_MSG
+// this value can be defined by the customer, but has to be
+// >= 64 bytes
+// however, if not defined before, we set a length of 64 byte
+#if !defined(CPC_MSG_LEN) || (CPC_MSG_LEN < 64)
+#undef CPC_MSG_LEN
+#define CPC_MSG_LEN 64
+#endif
+
+// check the operating system used
+#ifdef _WIN32 // running a Windows OS
+
+// define basic types on Windows platforms
+#ifdef _MSC_VER // Visual Studio
+       typedef unsigned __int8 u8;
+       typedef unsigned __int16 u16;
+       typedef unsigned __int32 u32;
+#else // Borland Compiler
+       typedef unsigned char u8;
+       typedef unsigned short u16;
+       typedef unsigned int u32;
+#endif
+       // on Windows OS we use a byte alignment of 1
+       #pragma pack(push, 1)
+
+       // set the calling conventions for the library function calls
+       #define CALL_CONV __stdcall
+#else
+       // Kernel headers already define this types
+       #ifndef __KERNEL__
+               // define basic types
+               typedef unsigned char u8;
+               typedef unsigned short u16;
+               typedef unsigned int u32;
+       #endif
+
+       // Linux does not use this calling convention
+       #define CALL_CONV
+#endif
+
+// Transmission of events from CPC interfaces to PC can be individually
+// controlled per event type. Default state is: don't transmit
+// Control values are constructed by bit-or of Subject and Action
+// and passed to CPC_Control()
+
+// Control-Values for CPC_Control() Command Subject Selection
+#define CONTR_CAN_Message 0x04
+#define CONTR_Busload    0x08
+#define        CONTR_CAN_State   0x0C
+#define        CONTR_SendAck     0x10
+#define        CONTR_Filter      0x14
+#define CONTR_CmdQueue    0x18 // reserved, do not use
+#define CONTR_BusError    0x1C
+
+// Control Command Actions
+#define CONTR_CONT_OFF    0
+#define CONTR_CONT_ON     1
+#define CONTR_SING_ON     2
+// CONTR_SING_ON doesn't change CONTR_CONT_ON state, so it should be
+// read as: transmit at least once
+
+// defines for confirmed request
+#define DO_NOT_CONFIRM 0
+#define DO_CONFIRM     1
+
+// event flags
+#define EVENT_READ 0x01
+#define EVENT_WRITE 0x02
+
+// Messages from CPC to PC contain a message object type field.
+// The following message types are sent by CPC and can be used in
+// handlers, others should be ignored.
+#define CPC_MSG_T_RESYNC        0 // Normally to be ignored
+#define CPC_MSG_T_CAN           1 // CAN data frame
+#define CPC_MSG_T_BUSLOAD       2 // Busload message
+#define CPC_MSG_T_STRING        3 // Normally to be ignored
+#define CPC_MSG_T_CONTI         4 // Normally to be ignored
+#define CPC_MSG_T_MEM           7 // Normally not to be handled
+#define        CPC_MSG_T_RTR           8 // CAN remote frame
+#define CPC_MSG_T_TXACK                9 // Send acknowledge
+#define CPC_MSG_T_POWERUP      10 // Power-up message
+#define        CPC_MSG_T_CMD_NO       11 // Normally to be ignored
+#define        CPC_MSG_T_CAN_PRMS     12 // Actual CAN parameters
+#define        CPC_MSG_T_ABORTED      13 // Command aborted message
+#define        CPC_MSG_T_CANSTATE     14 // CAN state message
+#define CPC_MSG_T_RESET        15 // used to reset CAN-Controller
+#define        CPC_MSG_T_XCAN         16 // XCAN data frame
+#define CPC_MSG_T_XRTR         17 // XCAN remote frame
+#define CPC_MSG_T_INFO         18 // information strings
+#define CPC_MSG_T_CONTROL      19 // used for control of
interface/driver behaviour
+#define CPC_MSG_T_CONFIRM      20 // response type for confirmed requests
+#define CPC_MSG_T_OVERRUN      21 // response type for overrun conditions
+#define CPC_MSG_T_KEEPALIVE    22 // response type for keep alive
conditions
+#define CPC_MSG_T_CANERROR     23 // response type for bus error conditions
+#define CPC_MSG_T_DISCONNECTED 24 // response type for a disconnected
interface
+#define CPC_MSG_T_ERR_COUNTER  25 // RX/TX error counter of CAN controller
+
+#define CPC_MSG_T_FIRMWARE    100 // response type for USB firmware
download
+
+// Messages from the PC to the CPC interface contain a command field
+// Most of the command types are wrapped by the library functions and
have therefore
+// normally not to be used.
+// However, programmers who wish to circumvent the library and talk
directly
+// to the drivers (mainly Linux programmers) can use the following
+// command types:
+
+#define CPC_CMD_T_CAN                 1        // CAN data frame
+#define CPC_CMD_T_CONTROL             3        // used for control of
interface/driver behaviour
+#define        CPC_CMD_T_CAN_PRMS            6 // set CAN parameters
+#define        CPC_CMD_T_CLEARBUF            8 // clears input queue; this is
depricated, use CPC_CMD_T_CLEAR_MSG_QUEUE instead
+#define        CPC_CMD_T_INQ_CAN_PARMS      11 // inquire actual CAN parameters
+#define        CPC_CMD_T_FILTER_PRMS        12 // set filter parameter
+#define        CPC_CMD_T_RTR                13 // CAN remote frame
+#define        CPC_CMD_T_CANSTATE           14 // CAN state message
+#define        CPC_CMD_T_XCAN               15 // XCAN data frame
+#define CPC_CMD_T_XRTR               16        // XCAN remote frame
+#define CPC_CMD_T_RESET              17        // used to reset CAN-Controller
+#define CPC_CMD_T_INQ_INFO           18        // miscellanous information 
strings
+#define CPC_CMD_T_OPEN_CHAN          19        // open a channel
+#define CPC_CMD_T_CLOSE_CHAN         20        // close a channel
+#define CPC_CMD_T_CNTBUF             21        // this is depricated, use
CPC_CMD_T_INQ_MSG_QUEUE_CNT instead
+#define CPC_CMD_T_CAN_EXIT          200 // exit the CAN (disable
interrupts; reset bootrate; reset output_cntr; mode = 1)
+
+#define CPC_CMD_T_INQ_MSG_QUEUE_CNT  CPC_CMD_T_CNTBUF   // inquires the
count of elements in the message queue
+#define CPC_CMD_T_INQ_ERR_COUNTER    25                        // request the
CAN controllers error counter
+#define        CPC_CMD_T_CLEAR_MSG_QUEUE    CPC_CMD_T_CLEARBUF // clear
CPC_MSG queue
+#define        CPC_CMD_T_CLEAR_CMD_QUEUE    28                 // clear
CPC_CMD queue
+#define CPC_CMD_T_FIRMWARE          100                 // reserved,
must not be used
+#define CPC_CMD_T_USB_RESET         101                 // reserved,
must not be used
+#define CPC_CMD_T_WAIT_NOTIFY       102                 // reserved,
must not be used
+#define CPC_CMD_T_WAIT_SETUP        103                 // reserved,
must not be used
+#define        CPC_CMD_T_ABORT             255                 // Normally not
to be used
+
+// definitions for CPC_MSG_T_INFO
+// information sources
+#define CPC_INFOMSG_T_UNKNOWN_SOURCE 0
+#define CPC_INFOMSG_T_INTERFACE      1
+#define CPC_INFOMSG_T_DRIVER         2
+#define CPC_INFOMSG_T_LIBRARY        3
+
+// information types
+#define CPC_INFOMSG_T_UNKNOWN_TYPE   0
+#define CPC_INFOMSG_T_VERSION        1
+#define CPC_INFOMSG_T_SERIAL         2
+
+// definitions for controller types
+#define PCA82C200   1 // Philips basic CAN controller, replaced by SJA1000
+#define SJA1000     2 // Philips basic CAN controller
+#define AN82527     3 // Intel full CAN controller
+#define M16C_BASIC  4 // M16C controller running in basic CAN (not full
CAN) mode
+
+// channel open error codes
+#define CPC_ERR_NO_FREE_CHANNEL            -1  // no more free space
within the channel array
+#define CPC_ERR_CHANNEL_ALREADY_OPEN       -2  // the channel is already
open
+#define CPC_ERR_CHANNEL_NOT_ACTIVE         -3  // access to a channel
not active failed
+#define CPC_ERR_NO_DRIVER_PRESENT          -4  // no driver at the
location searched by the library
+#define CPC_ERR_NO_INIFILE_PRESENT         -5  // the library could not
find the inifile
+#define CPC_ERR_WRONG_PARAMETERS           -6  // wrong parameters in
the inifile
+#define CPC_ERR_NO_INTERFACE_PRESENT       -7  // 1. The specified
interface is not connected
+                                               // 2. The interface (mostly 
CPC-USB) was disconnected upon operation
+#define CPC_ERR_NO_MATCHING_CHANNEL        -8  // the driver couldn't
find a matching channel
+#define CPC_ERR_NO_BUFFER_AVAILABLE        -9  // the driver couldn't
allocate buffer for messages
+#define CPC_ERR_NO_INTERRUPT               -10 // the requested
interrupt couldn't be claimed
+#define CPC_ERR_NO_MATCHING_INTERFACE      -11 // no interface type
related to this channel was found
+#define CPC_ERR_NO_RESOURCES               -12 // the requested
resources could not be claimed
+#define CPC_ERR_SOCKET                     -13 // error concerning TCP
sockets
+
+// init error codes
+#define CPC_ERR_WRONG_CONTROLLER_TYPE      -14 // wrong CAN controller
type within initialization
+#define CPC_ERR_NO_RESET_MODE              -15 // the controller could
not be set into reset mode
+#define CPC_ERR_NO_CAN_ACCESS              -16 // the CAN controller
could not be accessed
+
+// transmit error codes
+#define CPC_ERR_CAN_WRONG_ID               -20 // the provided CAN id
is too big
+#define CPC_ERR_CAN_WRONG_LENGTH           -21 // the provided CAN
length is too long
+#define CPC_ERR_CAN_NO_TRANSMIT_BUF        -22 // the transmit buffer
was occupied
+#define CPC_ERR_CAN_TRANSMIT_TIMEOUT       -23 // The message could not
be sent within a
+                                               // specified time
+
+// other error codes
+#define CPC_ERR_SERVICE_NOT_SUPPORTED      -30 // the requested service
is not supported by the interface
+#define CPC_ERR_IO_TRANSFER                -31 // a transmission error
down to the driver occurred
+#define CPC_ERR_TRANSMISSION_FAILED        -32 // a transmission error
down to the interface occurred
+#define CPC_ERR_TRANSMISSION_TIMEOUT       -33 // a timeout occurred
within transmission to the interface
+#define CPC_ERR_OP_SYS_NOT_SUPPORTED       -35 // the operating system
is not supported
+#define CPC_ERR_UNKNOWN                    -40 // an unknown error
ocurred (mostly IOCTL errors)
+
+#define CPC_ERR_LOADING_DLL                -50 // the library
'cpcwin.dll' could not be loaded
+#define CPC_ERR_ASSIGNING_FUNCTION         -51 // the specified
function could not be assigned
+#define CPC_ERR_DLL_INITIALIZATION         -52 // the DLL was not
initialized correctly
+#define CPC_ERR_MISSING_LICFILE            -55 // the file containing
the licenses does not exist
+#define CPC_ERR_MISSING_LICENSE            -56 // a required license
was not found
+
+// CAN state bit values. Ignore any bits not listed
+#define CPC_CAN_STATE_BUSOFF     0x80
+#define CPC_CAN_STATE_ERROR      0x40
+
+// Mask to help ignore undefined bits
+#define CPC_CAN_STATE_MASK       0xc0
+
+// CAN-Message representation in a CPC_MSG
+// Message object type is CPC_MSG_T_CAN or CPC_MSG_T_RTR
+// or CPC_MSG_T_XCAN or CPC_MSG_T_XRTR
+typedef struct CPC_CAN_MSG {
+       u32 id;
+       u8 length;
+       u8 msg[8];
+} CPC_CAN_MSG_T;
+
+
+// representation of the CAN parameters for the PCA82C200 controller
+typedef struct CPC_PCA82C200_PARAMS {
+       u8 acc_code;    // Acceptance-code for receive, Standard: 0
+       u8 acc_mask;    // Acceptance-mask for receive, Standard: 0xff 
(everything)
+       u8 btr0;        // Bus-timing register 0
+       u8 btr1;        // Bus-timing register 1
+       u8 outp_contr;  // Output-control register
+} CPC_PCA82C200_PARAMS_T;
+
+// representation of the CAN parameters for the SJA1000 controller
+typedef struct CPC_SJA1000_PARAMS {
+       u8 mode;        // enables single or dual acceptance filtering
+       u8 acc_code0;   // Acceptance-code for receive, Standard: 0
+       u8 acc_code1;
+       u8 acc_code2;
+       u8 acc_code3;
+       u8 acc_mask0;   // Acceptance-mask for receive, Standard: 0xff 
(everything)
+       u8 acc_mask1;
+       u8 acc_mask2;
+       u8 acc_mask3;
+       u8 btr0;        // Bus-timing register 0
+       u8 btr1;        // Bus-timing register 1
+       u8 outp_contr;  // Output-control register
+} CPC_SJA1000_PARAMS_T;
+
+// representation of the CAN parameters for the M16C controller
+// in basic CAN mode (means no full CAN)
+typedef struct CPC_M16C_BASIC_PARAMS {
+       u8 con0;
+       u8 con1;
+       u8 ctlr0;
+       u8 ctlr1;
+       u8 clk;
+       u8 acc_std_code0;
+       u8 acc_std_code1;
+       u8 acc_ext_code0;
+       u8 acc_ext_code1;
+       u8 acc_ext_code2;
+       u8 acc_ext_code3;
+       u8 acc_std_mask0;
+       u8 acc_std_mask1;
+       u8 acc_ext_mask0;
+       u8 acc_ext_mask1;
+       u8 acc_ext_mask2;
+       u8 acc_ext_mask3;
+} CPC_M16C_BASIC_PARAMS_T;
+
+// CAN params message representation
+typedef struct CPC_CAN_PARAMS {
+       u8 cc_type;     // represents the controller type
+       union {
+               CPC_M16C_BASIC_PARAMS_T m16c_basic;
+               CPC_SJA1000_PARAMS_T sja1000;
+               CPC_PCA82C200_PARAMS_T pca82c200;
+       } cc_params;
+} CPC_CAN_PARAMS_T;
+
+// the following structures are slightly different for Windows and Linux
+// To be able to use the 'Select' mechanism with Linux the application
+// needs to know the devices file desciptor.
+// This mechanism is not implemented within Windows and the file descriptor
+// is therefore not needed
+#ifdef _WIN32
+
+// CAN init params message representation
+typedef struct CPC_INIT_PARAMS {
+       CPC_CAN_PARAMS_T canparams;
+} CPC_INIT_PARAMS_T;
+
+#else// Linux
+
+// CHAN init params representation
+typedef struct CPC_CHAN_PARAMS {
+       int fd;
+} CPC_CHAN_PARAMS_T;
+
+// CAN init params message representation
+typedef struct CPC_INIT_PARAMS {
+       CPC_CHAN_PARAMS_T chanparams;
+       CPC_CAN_PARAMS_T canparams;
+} CPC_INIT_PARAMS_T;
+
+#endif
+
+// structure for confirmed message handling
+typedef struct CPC_CONFIRM {
+       u8 result; // error code
+} CPC_CONFIRM_T;
+
+// structure for information requests
+typedef struct CPC_INFO {
+       u8 source;                 // interface, driver or library
+       u8 type;                   // version or serial number
+       char msg[CPC_MSG_LEN - 2]; // string holding the requested information
+} CPC_INFO_T;
+
+// OVERRUN ///////////////////////////////////////
+// In general two types of overrun may occur.
+// A hardware overrun, where the CAN controller
+// lost a message, because the interrupt was
+// not handled before the next messgae comes in.
+// Or a software overrun, where i.e. a received
+// message could not be stored in the CPC_MSG
+// buffer.
+
+// After a software overrun has occurred
+// we wait until we have CPC_OVR_GAP slots
+// free in the CPC_MSG buffer.
+#define CPC_OVR_GAP               10
+
+// Two types of software overrun may occur.
+// A received CAN message or a CAN state event
+// can cause an overrun.
+// Note: A CPC_CMD which would normally store
+// its result immediately in the CPC_MSG
+// queue may fail, because the message queue is full.
+// This will not generate an overrun message, but
+// will halt command execution, until this command
+// is able to store its message in the message queue.
+#define CPC_OVR_EVENT_CAN       0x01
+#define CPC_OVR_EVENT_CANSTATE  0x02
+#define CPC_OVR_EVENT_BUSERROR  0x04
+
+// If the CAN controller lost a message
+// we indicate it with the highest bit
+// set in the count field.
+#define CPC_OVR_HW              0x80
+
+// structure for overrun conditions
+typedef struct {
+       u8 event;
+       u8 count;
+} CPC_OVERRUN_T;
+
+// CAN errors ////////////////////////////////////
+// Each CAN controller type has different
+// registers to record errors.
+// Therefor a structure containing the specific
+// errors is set up for each controller here
+
+// SJA1000 error structure
+// see the SJA1000 datasheet for detailed
+// explanation of the registers
+typedef struct CPC_SJA1000_CAN_ERROR {
+       u8 ecc;   // error capture code register
+       u8 rxerr; // RX error counter register
+       u8 txerr; // TX error counter register
+} CPC_SJA1000_CAN_ERROR_T;
+
+// M16C error structure
+// see the M16C datasheet for detailed
+// explanation of the registers
+typedef struct CPC_M16C_CAN_ERROR {
+       u8 tbd; // to be defined
+} CPC_M16C_CAN_ERROR_T;
+
+// structure for CAN error conditions
+#define  CPC_CAN_ECODE_ERRFRAME   0x01
+typedef struct CPC_CAN_ERROR {
+       u8 ecode;
+       struct {
+               u8 cc_type; // CAN controller type
+               union {
+                       CPC_SJA1000_CAN_ERROR_T sja1000;
+                       CPC_M16C_CAN_ERROR_T m16c;
+               } regs;
+       } cc;
+} CPC_CAN_ERROR_T;
+
+// Structure containing RX/TX error counter.
+// This structure is used to request the
+// values of the CAN controllers TX and RX
+// error counter.
+typedef struct CPC_CAN_ERR_COUNTER {
+       u8 rx;
+       u8 tx;
+} CPC_CAN_ERR_COUNTER_T;
+
+// If this flag is set, transmissions from PC to CPC are protected
against loss
+#define CPC_SECURE_TO_CPC      0x01
+
+// If this flag is set, transmissions from CPC to PC are protected
against loss
+#define CPC_SECURE_TO_PC       0x02
+
+// If this flag is set, the CAN-transmit buffer is checked to be free
before sending a message
+#define CPC_SECURE_SEND                0x04
+
+// If this flag is set, the transmission complete flag is checked
+// after sending a message
+// THIS IS CURRENTLY ONLY IMPLEMENTED IN THE PASSIVE INTERFACE DRIVERS
+#define CPC_SECURE_TRANSMIT    0x08
+
+// main message type used between library and application
+typedef struct CPC_MSG {
+       u8 type;        // type of message
+       u8 length;      // length of data within union 'msg'
+       u8 msgid;       // confirmation handle
+       u32 ts_sec;     // timestamp in seconds
+       u32 ts_nsec;    // timestamp in nano seconds
+       union {
+               u8 generic[CPC_MSG_LEN];
+               CPC_CAN_MSG_T canmsg;
+               CPC_CAN_PARAMS_T canparams;
+               CPC_CONFIRM_T confirmation;
+               CPC_INFO_T info;
+               CPC_OVERRUN_T overrun;
+               CPC_CAN_ERROR_T error;
+               CPC_CAN_ERR_COUNTER_T err_counter;
+               u8 busload;
+               u8 canstate;
+       } msg;
+} CPC_MSG_T;
+
+#ifdef _WIN32
+#pragma pack(pop)              // reset the byte alignment
+#endif
+
+#endif                         // CPC_HEADER
Index: Makefile
===================================================================
- --- Makefile  (Revision 1048)
+++ Makefile    (Arbeitskopie)
@@ -4,34 +4,35 @@
 PWD       := $(shell pwd)
 TOPDIR    := $(PWD)

- -export CONFIG_CAN_VCAN=m
+export CONFIG_CAN_VCAN=n
 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=n
+export CONFIG_CAN_SJA1000_PLATFORM=n
 #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
- -export CONFIG_CAN_MCP251X=m
+export CONFIG_CAN_ESD_PCI=n
+export CONFIG_CAN_IXXAT_PCI=n
+export CONFIG_CAN_PEAK_PCI=n
+export CONFIG_CAN_KVASER_PCI=n
+export CONFIG_CAN_EMS_PCI=n
+export CONFIG_CAN_EMS_USB=m
+export CONFIG_CAN_EMS_PCMCIA=n
+export CONFIG_CAN_EMS_104M=n
+export CONFIG_CAN_ESD_PCI=n
+export CONFIG_CAN_ESD_331=n
+export CONFIG_CAN_PIPCAN=n
+export CONFIG_CAN_SOFTING=n
+export CONFIG_CAN_SOFTING_CS=n
+export CONFIG_CAN_MCP251X=n

 export CONFIG_CAN=m
 export CONFIG_CAN_RAW=m
- -export CONFIG_CAN_BCM=m
- -export CONFIG_CAN_ISOTP=m
+export CONFIG_CAN_BCM=n
+export CONFIG_CAN_ISOTP=n

 modules modules_install clean:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) $@ TOPDIR=$(TOPDIR)
Index: drivers/net/can/Makefile
===================================================================
- --- drivers/net/can/Makefile  (Revision 1048)
+++ drivers/net/can/Makefile    (Arbeitskopie)
@@ -49,6 +49,7 @@
 obj-$(CONFIG_CAN_MSCAN_OLD)    += old/mscan/
 obj-$(CONFIG_CAN_CCAN_OLD)     += old/ccan/
 obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
+obj-$(CONFIG_CAN_EMS_USB)      += ems_usb.o

 ifeq ($(CONFIG_CAN_DEBUG_DEVICES),y)
        EXTRA_CFLAGS += -DDEBUG
Index: drivers/net/can/ems_usb.c
===================================================================
- --- drivers/net/can/ems_usb.c (Revision 0)
+++ drivers/net/can/ems_usb.c   (Revision 0)
@@ -0,0 +1,668 @@
+/*
+ * CPC-USB CAN Interface Kernel Driver
+ *
+ * Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+#include <socketcan/can.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/error.h>
+#include <socketcan/can/dev.h>
+
+#include <linux/cpc.h>
+
+MODULE_AUTHOR("Sebastian Haas <[email protected]>");
+MODULE_DESCRIPTION("CPC-USB Driver for Linux Kernel 2.6");
+MODULE_VERSION("0.0");
+MODULE_LICENSE("GPL v2");
+
+/* Define these values to match your devices */
+#define USB_CPCUSB_VENDOR_ID   0x12D6
+
+#define USB_CPCUSB_M16C_PRODUCT_ID    0x0888
+#define USB_CPCUSB_LPC2119_PRODUCT_ID 0x0444
+
+/* table of devices that work with this driver */
+static struct usb_device_id ems_usb_table[] = {
+       {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_M16C_PRODUCT_ID)},
+       {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_LPC2119_PRODUCT_ID)},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ems_usb_table);
+
+#define CPC_MSG_HEADER_LEN 11
+
+#define RX_BUFFER_SIZE 64
+#define HEADER_SIZE    4
+
+struct ems_usb {
+       struct can_priv can;    /* must be the first member */
+
+       int open_time;
+
+       struct usb_device *udev;
+       struct net_device *netdev;
+
+       struct urb *rx_urb, *tx_urb, *intr_urb;
+
+       __u8 *rx_buffer;
+
+       __u8 *tx_msg_buffer; /* Buffer for synchronous commands */
+
+       __u8 intr_in_buffer[4];
+       unsigned int free_slots; /* Remember number of freely available slots */
+
+       CPC_MSG_T active_params; /* Current state of controller parameters */
+};
+
+#define GET_PARAMS(d) d->active_params.msg.canparams.cc_params.sja1000
+
+#define MOD_RM 0x01
+
+static void init_params(CPC_MSG_T *msg, __u8 btr0, __u8 btr1,
+                        __u8 outp, __u8 mod)
+{
+       msg->type = CPC_CMD_T_CAN_PRMS;
+       msg->length = CPC_MSG_HEADER_LEN + sizeof(CPC_CAN_PARAMS_T);
+       msg->msgid = 0;
+
+       msg->msg.canparams.cc_type = SJA1000;
+
+       msg->msg.canparams.cc_params.sja1000.acc_code0 = 0;
+       msg->msg.canparams.cc_params.sja1000.acc_code1 = 0;
+       msg->msg.canparams.cc_params.sja1000.acc_code2 = 0;
+       msg->msg.canparams.cc_params.sja1000.acc_code3 = 0;
+
+       msg->msg.canparams.cc_params.sja1000.acc_mask0 = 0xFF;
+       msg->msg.canparams.cc_params.sja1000.acc_mask1 = 0xFF;
+       msg->msg.canparams.cc_params.sja1000.acc_mask2 = 0xFF;
+       msg->msg.canparams.cc_params.sja1000.acc_mask3 = 0xFF;
+
+       msg->msg.canparams.cc_params.sja1000.btr0 = btr0;
+       msg->msg.canparams.cc_params.sja1000.btr1 = btr1;
+
+       msg->msg.canparams.cc_params.sja1000.outp_contr = outp;
+       msg->msg.canparams.cc_params.sja1000.mode = mod;
+}
+
+static void ems_usb_read_interrupt_callback(struct urb *urb)
+{
+       struct ems_usb *dev = urb->context;
+       struct net_device *netdev;
+
+       int retval;
+
+       netdev = dev->netdev;
+
+       if (!netif_device_present(netdev))
+               return;
+
+       switch (urb->status) {
+       case 0:
+               dev->free_slots = dev->intr_in_buffer[1];
+               break;
+
+       case -ECONNRESET:/* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+
+       default:
+               dev_info(ND2D(netdev), "nonzero urb status %d\n", urb->status);
+               break;
+       }
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval == -ENODEV)
+               netif_device_detach(netdev);
+       else if(retval)
+               dev_err(ND2D(netdev), "failed resubmitting intr urb: %d\n", 
retval);
+
+       return;
+}
+
+static int inline unalign_n_copy(__u8 *out, __u8 *in)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < 3; i++)
+               out[i] = in[i];
+
+       for (j = 0; j < (in[1] + (CPC_MSG_HEADER_LEN - 3)); j++)
+               out[j + i + 1] = in[j + i];
+
+       return i + j;
+}
+
+static void ems_usb_rx_canmsg(struct ems_usb *dev, CPC_MSG_T *msg)
+{
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       int i;
+
+       struct net_device_stats *stats = &dev->netdev->stats;
+
+       skb = dev_alloc_skb(sizeof(struct can_frame));
+       if (skb == NULL)
+               return;
+
+       skb->dev = dev->netdev;
+       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  = msg->msg.canmsg.id;
+       cf->can_dlc = msg->msg.canmsg.length > 8 ? 8 : msg->msg.canmsg.length;
+
+       if(msg->type == CPC_MSG_T_XCAN || msg->type == CPC_MSG_T_XRTR)
+               cf->can_id |= CAN_EFF_FLAG;
+
+       if(msg->type == CPC_MSG_T_RTR || msg->type == CPC_MSG_T_XRTR) {
+               cf->can_id |= CAN_RTR_FLAG;
+       } else {
+               for (i = 0; i < cf->can_dlc; i++)
+                       cf->data[i] = msg->msg.canmsg.msg[i];
+
+               /* Clear remaining bytes */
+               while (i < 8)
+                       cf->data[i++] = 0;
+       }
+
+       netif_rx(skb);
+
+       dev->netdev->last_rx = jiffies;
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+}
+
+/*
+ * callback for bulk IN urb
+ */
+static void ems_usb_read_bulk_callback(struct urb *urb)
+{
+       struct ems_usb *dev = urb->context;
+       struct net_device *netdev;
+
+       int retval;
+
+       netdev = dev->netdev;
+
+       if (!netif_device_present(netdev))
+               return;
+
+       switch (urb->status) {
+       case 0:         /* success */
+               break;
+
+       case -ENOENT:
+               return;
+
+       default:
+               dev_warn(ND2D(netdev), "nonzero URB status %d", urb->status);
+               goto resubmit_urb;
+       }
+
+       if (urb->actual_length > HEADER_SIZE) {
+               CPC_MSG_T msg;
+
+               __u8 *ibuf = urb->transfer_buffer;
+
+               __u8 msgCnt, again, start;
+
+               msgCnt = ibuf[0] & ~0x80;
+               again = ibuf[0] & 0x80;
+
+               start = HEADER_SIZE;
+
+               while (msgCnt) {
+                       start += unalign_n_copy((__u8 *)&msg, &ibuf[start]);
+
+                       switch(msg.type) {
+                       case CPC_MSG_T_CANSTATE:
+                               /* TODO: Process CAN state changes */
+                               break;
+
+                       case CPC_MSG_T_CAN:
+                       case CPC_MSG_T_XCAN:
+                       case CPC_MSG_T_RTR:
+                       case CPC_MSG_T_XRTR:
+                               ems_usb_rx_canmsg(dev, &msg);
+                               break;
+
+                       case CPC_MSG_T_CANERROR:
+                               /* TODO: Process errorframe */
+                               break;
+
+                       case CPC_MSG_T_OVERRUN:
+                               /* TODO: Message lost while receiving */
+                               break;
+                       }
+
+                       if (start > urb->transfer_buffer_length) {
+                               err("%d > %d", start, 
urb->transfer_buffer_length);
+                               break;
+                       }
+
+                       msgCnt--;
+               }
+       }
+
+resubmit_urb:
+       usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
+                       dev->rx_buffer, RX_BUFFER_SIZE, 
ems_usb_read_bulk_callback, dev);
+
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval == -ENODEV)
+               netif_device_detach(netdev);
+       else if(retval)
+               dev_err(ND2D(netdev), "failed resubmitting bulk urb: %d\n", 
retval);
+
+       return;
+}
+
+/*
+ * callback for bulk IN urb
+ */
+static void ems_usb_write_bulk_callback(struct urb *urb)
+{
+       return;
+}
+
+static void inline align_buffer(CPC_MSG_T *msg)
+{
+       unsigned int i;
+
+       for (i = 0; i < msg->length + (2 * sizeof(unsigned long)); i++) {
+               ((__u8 *)&msg->msgid)[1 + i] =
+                   ((__u8 *)&msg->msgid)[2 + i];
+       }
+}
+
+static void prepare_command(__u8 *buf, CPC_MSG_T *msg)
+{
+       memcpy(&buf[HEADER_SIZE], msg, msg->length + CPC_MSG_HEADER_LEN);
+
+       align_buffer((CPC_MSG_T *)&buf[HEADER_SIZE]);
+
+       /* Clear header */
+       memset(&buf[HEADER_SIZE], 0, HEADER_SIZE);
+}
+
+/**
+ * Send the given CPC command synchronously
+ */
+static int ems_usb_command_msg(struct ems_usb *dev, CPC_MSG_T *msg)
+{
+       int actual_length;
+
+       prepare_command(&dev->tx_msg_buffer[0], msg);
+
+       return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+                           &dev->tx_msg_buffer[0],
+                           msg->length + CPC_MSG_HEADER_LEN + HEADER_SIZE,
+                           &actual_length, 1000);
+}
+
+static int ems_usb_control_cmd(struct ems_usb *dev, __u8 val)
+{
+       CPC_MSG_T cmd;
+
+       cmd.type = CPC_CMD_T_CONTROL;
+       cmd.length = CPC_MSG_HEADER_LEN + 1;
+
+       cmd.msgid = 0;
+
+       cmd.msg.generic[0] = val;
+
+       return ems_usb_command_msg(dev, &cmd);
+}
+
+static int ems_usb_open(struct net_device *netdev)
+{
+       struct ems_usb *dev = netdev_priv(netdev);
+       int result;
+
+       dev->can.state = CAN_STATE_STOPPED;
+
+       dev->intr_in_buffer[0] = 0;
+       dev->free_slots = 15; /* initial size */
+
+       usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
+                       dev->rx_buffer, RX_BUFFER_SIZE, 
ems_usb_read_bulk_callback, dev);
+
+       result = usb_submit_urb(dev->rx_urb, GFP_KERNEL);
+       if (result) {
+               if (result == -ENODEV)
+                       netif_device_detach(dev->netdev);
+
+               dev_warn(ND2D(netdev), "rx_urb submit failed: %d\n", result);
+
+               return result;
+       }
+
+       /* Setup and start interrupt URB */
+       usb_fill_int_urb(dev->intr_urb, dev->udev,
+                        usb_rcvintpipe(dev->udev, 1),
+                        dev->intr_in_buffer, sizeof(dev->intr_in_buffer),
+                        ems_usb_read_interrupt_callback, dev, 10);
+
+       result = usb_submit_urb(dev->intr_urb, GFP_KERNEL);
+       if (result) {
+               if (result == -ENODEV)
+                       netif_device_detach(dev->netdev);
+
+               dev_warn(ND2D(netdev), "intr urb submit failed: %d\n", result);
+
+               usb_kill_urb(dev->rx_urb);
+
+               return result;
+       }
+
+       /* CPC-USB will transfer received message to host */
+       result = ems_usb_control_cmd(dev, CONTR_CAN_Message | CONTR_CONT_ON);
+       if(result)
+               goto failed;
+
+       /* CPC-USB will transfer CAN state changes to host */
+       result = ems_usb_control_cmd(dev, CONTR_CAN_State | CONTR_CONT_ON);
+       if(result)
+               goto failed;
+
+       /* CPC-USB will transfer bus errors to host */
+       result = ems_usb_control_cmd(dev, CONTR_BusError | CONTR_CONT_ON);
+       if(result)
+               goto failed;
+
+       /* common open */
+       result = open_candev(netdev);
+       if (result)
+               goto failed;
+
+       dev->open_time = jiffies;
+
+       netif_start_queue(netdev);
+
+       return 0;
+
+failed:
+       if (result == -ENODEV)
+               netif_device_detach(dev->netdev);
+
+       dev_warn(ND2D(netdev), "couldn't submit control: %d\n", result);
+
+       return result;
+}
+
+static int ems_usb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       // TODO: Create tx buffer and send
+
+       return 0;
+}
+
+static int ems_usb_close(struct net_device *dev)
+{
+       struct ems_usb *priv = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+
+       GET_PARAMS(priv).mode = MOD_RM;
+
+       if(ems_usb_command_msg(priv, &priv->active_params))
+               dev_warn(ND2D(dev), "couldn't stop device");
+
+       close_candev(dev);
+
+       priv->open_time = 0;
+
+       return 0;
+}
+
+static int alloc_all_urbs(struct ems_usb *dev)
+{
+       dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->rx_urb)
+               return 0;
+
+       dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->tx_urb) {
+               usb_free_urb(dev->rx_urb);
+               return 0;
+       }
+
+       dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->intr_urb) {
+               usb_free_urb(dev->rx_urb);
+               usb_free_urb(dev->tx_urb);
+               return 0;
+       }
+
+       return 1;
+}
+
+static void free_all_urbs(struct ems_usb *dev)
+{
+       usb_free_urb(dev->rx_urb);
+       usb_free_urb(dev->tx_urb);
+       usb_free_urb(dev->intr_urb);
+}
+
+static void unlink_all_urbs(struct ems_usb *dev)
+{
+       usb_unlink_urb(dev->rx_urb);
+       usb_unlink_urb(dev->tx_urb);
+       usb_unlink_urb(dev->intr_urb);
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops ems_usb_netdev_ops = {
+       .ndo_open       = ems_usb_open,
+       .ndo_stop       = ems_usb_close,
+       .ndo_start_xmit = ems_usb_start_xmit,
+};
+#endif
+
+static struct can_bittiming_const ems_usb_bittiming_const = {
+       .name = "ems_usb",
+       .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 int ems_usb_set_mode(struct net_device *dev, enum can_mode mode)
+{
+       struct ems_usb *priv = netdev_priv(dev);
+
+       if (!priv->open_time)
+               return -EINVAL;
+
+       switch (mode) {
+       case CAN_MODE_START:
+               GET_PARAMS(priv).mode = 0;
+
+               if(ems_usb_command_msg(priv, &priv->active_params))
+                       dev_warn(ND2D(dev), "couldn't start device");
+
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int ems_usb_set_bittiming(struct net_device *dev)
+{
+       struct ems_usb *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);
+
+       GET_PARAMS(priv).btr0 = btr0;
+       GET_PARAMS(priv).btr1 = btr1;
+
+       return ems_usb_command_msg(priv, &priv->active_params);
+}
+
+/*
+ * probe function for new CPC-USB devices
+ */
+static int ems_usb_probe(struct usb_interface *intf,
+                         const struct usb_device_id *id)
+{
+       struct net_device *dev;
+       struct ems_usb *priv;
+       int result;
+
+       dev = alloc_candev(sizeof(struct ems_usb));
+       if (!dev) {
+               err("Out of memory");
+               return -ENOMEM;
+       }
+
+       priv = netdev_priv(dev);
+
+       priv->udev = interface_to_usbdev(intf);
+       priv->netdev = dev;
+
+       priv->can.bittiming_const  = &ems_usb_bittiming_const;
+       priv->can.do_set_bittiming = &ems_usb_set_bittiming;
+       priv->can.do_set_mode      = &ems_usb_set_mode;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+       dev->netdev_ops = &ems_usb_netdev_ops;
+#else
+       dev->open = ems_usb_open;
+       dev->stop = ems_usb_close;
+       dev->hard_start_xmit = ems_usb_start_xmit;
+#endif
+
+       // TODO: Which flags to we support?
+       dev->flags |= IFF_ECHO; /* we support local echo */
+
+       if (!alloc_all_urbs(priv)) {
+               err("Out of memory");
+               free_candev(dev);
+               return -ENOMEM;
+       }
+
+       priv->rx_buffer = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
+       if (!priv->rx_buffer) {
+               err("Out of memory");
+               free_candev(dev);
+               free_all_urbs(priv);
+               return -ENOMEM;
+       }
+
+       priv->tx_msg_buffer = kzalloc(sizeof(CPC_MSG_T) + HEADER_SIZE,
GFP_KERNEL);
+       if (!priv->tx_msg_buffer) {
+               err("Out of memory");
+               free_candev(dev);
+               free_all_urbs(priv);
+               kfree(priv->rx_buffer);
+               return -ENOMEM;
+       }
+
+       usb_set_intfdata(intf, priv);
+
+       SET_NETDEV_DEV(dev, &intf->dev);
+
+       init_params(&priv->active_params, 0x00, 0x00, 0xDA, MOD_RM);
+       result = ems_usb_command_msg(priv, &priv->active_params);
+
+       if(result)
+               dev_warn(ND2D(dev), "couldn't initialize controller: %d\n", 
result);
+
+       return register_candev(dev);
+}
+
+/*
+ * called by the usb core when the device is removed from the system
+ */
+static void ems_usb_disconnect(struct usb_interface *intf)
+{
+       struct ems_usb *dev = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+
+       if (dev) {
+               unregister_netdev(dev->netdev);
+               free_candev(dev->netdev);
+
+               unlink_all_urbs(dev);
+               free_all_urbs(dev);
+       }
+}
+
+/* usb specific object needed to register this driver with the usb
subsystem */
+static struct usb_driver ems_usb_driver = {
+       .name       = "ems_usb",
+       .probe      = ems_usb_probe,
+       .disconnect = ems_usb_disconnect,
+       .id_table   = ems_usb_table,
+};
+
+static int __init ems_usb_init(void)
+{
+       int result;
+
+       printk(KERN_INFO "CPC-USB kernel driver loaded\n");
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&ems_usb_driver);
+
+       if (result) {
+               err("usb_register failed. Error number %d", result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit ems_usb_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&ems_usb_driver);
+}
+
+module_init(ems_usb_init);
+module_exit(ems_usb_exit);
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkqlKfgACgkQpqRB8PJG7XwxrQCfR4Xgdy/HPh7RmQqeYqMppClJ
Q1UAn3p9W5aJL1ZW2XVd4jTl2TGsjEpP
=b2M9
-----END PGP SIGNATURE-----
-- 
EMS Dr. Thomas Wuensche e.K.
Sonnenhang 3
85304 Ilmmuenster
HRA Neuburg a.d. Donau, HR-Nr. 70.106
Phone: +49-8441-490260
Fax  : +49-8441-81860
http://www.ems-wuensche.com
_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to