The first phase of integration of Hynix HMS30c7202 C_CAN support
authorppisa <ppisa>
Sun, 6 Jun 2004 03:23:21 +0000 (03:23 +0000)
committerppisa <ppisa>
Sun, 6 Jun 2004 03:23:21 +0000 (03:23 +0000)
lincan/include/c_can.h [new file with mode: 0644]
lincan/include/constants.h
lincan/include/hms30c7202_can.h [new file with mode: 0644]
lincan/include/main.h
lincan/src/c_can.c [new file with mode: 0644]
lincan/src/c_can_irq.c [new file with mode: 0644]
lincan/src/hms30c7202_can.c [new file with mode: 0644]
lincan/src/i82527.c
lincan/src/pcm3680.c
lincan/src/unican.c

diff --git a/lincan/include/c_can.h b/lincan/include/c_can.h
new file mode 100644 (file)
index 0000000..4955d86
--- /dev/null
@@ -0,0 +1,247 @@
+/* c_can.h - Hynix HMS30c7202 ARM generic C_CAN module handling
+ * Linux CAN-bus device driver.
+ * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de
+ * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
+ * and Ake Hedman, eurosource, akhe@eurosource.se
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2  9 Jul 2003
+ */
+
+void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg);
+
+u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg);
+
+#ifndef CONFIG_OC_LINCAN_DYNAMICIO
+/* 
+ * optimized inline version, may it be, that it can be too fast for the chip
+ */
+extern inline void c_can_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg)
+{
+       u32 address = pchip->chip_base_addr + reg;
+       writew(data,address);
+}
+
+extern inline u16 c_can_read_reg_w(const struct chip_t *pchip, unsigned reg)
+{
+       u32 address = pchip->chip_base_addr + reg;
+       return readw(address);
+}
+#else /*CONFIG_OC_LINCAN_DYNAMICIO*/
+/* 
+ * the standard routines for register access cannot be used,
+ * because they work only with 8-bit peripherals
+ */
+
+extern inline void c_can_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg)
+{
+       hms30c7202_write_reg_w(pchip, data, reg);
+}
+
+extern inline u16 c_can_read_reg_w(const struct chip_t *pchip, unsigned reg)
+{
+       return hms30c7202_read_reg_w(pchip, reg);
+}
+#endif /*CONFIG_OC_LINCAN_DYNAMICIO*/
+
+extern can_spinlock_t c_can_spwlock; // Spin lock for write operations
+extern can_spinlock_t c_can_sprlock; // Spin lock for read operations
+extern can_spinlock_t c_can_if1lock; // spin lock for the if1 register
+extern can_spinlock_t c_can_if2lock; // spin lcok for the if2 register
+
+int c_can_if1_busycheck(struct chip_t *pchip);
+int c_can_if2_busycheck(struct chip_t *pchip);
+
+int c_can_enable_configuration(struct chip_t *pchip);
+int c_can_disable_configuration(struct chip_t *pchip);
+int c_can_chip_config(struct chip_t *pchip);
+int c_can_baud_rate(struct chip_t *chip, int rate, int clock,
+                       int sjw, int sampl_pt, int flags);
+int c_can_mask(struct msgobj_t *pmsgobj,
+              u32 mask,
+              u16 usedirbit);
+int c_can_use_mask(struct msgobj_t *pmsgobj,
+                  u16 useflag);
+int c_can_clear_objects(struct chip_t *pchip);
+int c_can_config_irqs(struct chip_t *pchip,
+                      u16 irqs);
+int c_can_pre_read_config(struct chip_t *chip, struct msgobj_t *obj);
+int c_can_send_msg(struct chip_t *pchip, struct msgobj_t *pmsgobj,
+                       struct canmsg_t *pmsg);
+int c_can_remote_request(struct chip_t *pchip, struct msgobj_t *pmsgobj );
+int c_can_set_btregs(struct chip_t *chip,
+                     u16 btr0,
+                    u16 btr1);
+int c_can_start_chip(struct chip_t *pchip);
+int c_can_stop_chip(struct chip_t *pchip);
+int c_can_check_tx_stat(struct chip_t *pchip);
+
+int c_can_register(struct chipspecops_t *chipspecops);
+
+void c_can_registerdump(struct chip_t *pchip);
+
+void c_can_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj);
+
+can_irqreturn_t c_can_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+/* BasicCAN mode address map */
+#define CCCR      0x0000       /* Control Register */
+#define CCSR           0x0004  /* Status Register */
+#define CCEC           0x0008  /* Error Counting Register */
+#define CCBT           0x000C  /* Bit Timing Register */
+#define CCINTR         0x0010  /* Interrupt Register */
+#define CCTR           0x0014  /* Test Register */
+#define CCBRPE         0x0018  /* Baud Rate Prescaler Extension Register */
+#define CCCE           0x001C  /* CAN Enable Register */
+#define CCTREQ1        0x0100  /* Transmission Request 1 Register */
+#define CCTREQ2        0x0104  /* Transmission Request 2 Register */
+#define CCND1     0x0120       /* New Data 1 Register */
+#define CCND2     0x0124       /* New Data 2 Register */
+#define CCINTP1        0x0140  /* Interrupt Pending 1 Register */
+#define CCINTP2        0x0144  /* Interrupt Pending 2 Register */
+
+#define CCIF1CR        0x0020  /* Interface 1 Command Request Register */
+#define CCIF1CM        0x0024  /* IF1 Command Mask Register */
+#define CCIF1M1        0x0028  /* IF1 Mask 1 Register */
+#define CCIF1M2        0x002C  /* IF1 Mask 2 Register */
+#define CCIF1A1        0x0030  /* IF1 Arbitration 1 Register */
+#define CCIF1A2        0x0034  /* IF1 Arbitration 2 Register */
+#define CCIF1DMC       0x0038  /* IF1 Message Control Register */
+#define CCIF1DA1       0x003C  /* IF1 Data A 1 Register */
+#define CCIF1DA2       0x0040  /* IF1 Data A 2 Register */
+#define CCIF1DB1       0x0044  /* IF1 Data B 1 Register */
+#define CCIF1DB2       0x0048  /* IF1 Data B 2 Register */
+
+#define CCIF2CR        0x0080  /* Interface 2 Command Request Register */
+#define CCIF2CM        0x0084  /* IF2 Command Mask Register */
+#define CCIF2M1        0x0088  /* IF2 Mask 1 Register */
+#define CCIF2M2        0x008C  /* IF2 Mask 2 Register */
+#define CCIF2A1        0x0090  /* IF2 Arbitration 1 Register */
+#define CCIF2A2        0x0094  /* IF2 Arbitration 2 Register */
+#define CCIF2DMC       0x0098  /* IF2 Message Control Register */
+#define CCIF2DA1       0x009C  /* IF2 Data A 1 Register */
+#define CCIF2DA2       0x00A0  /* IF2 Data A 2 Register */
+#define CCIF2DB1       0x00A4  /* IF2 Data B 1 Register */
+#define CCIF2DB2       0x00A8  /* IF2 Data B 2 Register */
+
+/* Control register */
+enum c_can_BASIC_CR
+{
+   CR_INIT = 1,                // Internal Initialization Pending
+     CR_MIE  = 1<<1,  // Module Interrupt Enable
+     CR_SIE  = 1<<2,   // Status-change Interrupt Enable
+     CR_EIE  = 1<<3,   // Error Interrupt Enable
+     CR_DAR  = 1<<5,   // Disable Automatic Retransmission
+     CR_CCE  = 1<<6,  // Configuration Change Enable
+     CR_TEST = 1<<7   // Test Mode Enable
+};
+
+/* Status Register */
+enum c_can_BASIC_SR
+{
+   SR_TXOK  = 1<<3,    // Transmitted a Message Successfully
+     SR_RXOK  = 1<<4,  // Received a Message Successfully
+     SR_EPASS = 1<<5,  // Error Passive
+     SR_EWARN = 1<<6,  // Error Warning Status
+     SR_BOFF  = 1<<7,  // Bus Off Status
+};
+
+/* Status Register Last Error Codes */
+enum c_can_BASIC_SRLEC
+{
+   SRLEC_NE = 0,     // Last Error Code: No Error
+     SRLEC_SE = 1,     // LEC: Stuff Error
+     SRLEC_FE = 2,     // LEC: Form Error
+     SRLEC_AE = 3,     // LEC: Acknowledgement Error
+     SRLEC_B1 = 4,     // LEC: Bit1 Error
+     SRLEC_B0 = 5,     // LEC: Bit0 Error
+     SRLEC_CR = 6      // LEC: CRC Error
+};
+
+/* Error Counting Register */
+enum c_can_BASIC_EC
+{
+   EC_REP = 1<<15              // Receive Error Passive
+};
+
+/* Interrupt Register */
+enum c_can_BASIC_INT
+{
+   INT_NOINT = 0,                 // No Interrupt is pending
+     INT_STAT  = 0x8000   // Status Interrupt
+};
+
+/* CAN Test Register */
+enum c_can_BASIC_TR
+{
+   TR_BASIC = 1<<2,  // Basic Mode
+     TR_SLNT  = 1<<3,  // Silent Mode
+     TR_LOOPB = 1<<4,  // Loop Back Mode
+     TR_RX    = 1<<7   // Receive (CAN_RX Pin)
+};
+
+/* CAN Test Register TX Control*/
+enum c_can_BASIC_TRTX
+{
+   TRTX_RST = 0,     // Reset value, CAN_TX is controlled by the CAN Core
+     TRTX_MON = 1,     // Sample Point can be monitored at CAN_TX pin
+     TRTX_DOM = 2,     // CAN_TX pin drives a dominant('0') value
+     TRTX_REC = 3      // CAN_TX pin drives a recessive('1') value
+};
+
+/* CAN Enable Register */
+enum c_can_BASIC_CE
+{
+   CE_EN  = 1                  // CAN Enable Bit
+};
+
+/* Interface X Command Request Register */
+enum c_can_BASIC_IFXCR
+{
+   IFXCR_BUSY = 1<<15   // Busy Flag (Write Access only when Busy='0')
+};
+
+/* Interface X Command Mask Register */
+enum c_can_BASIC_IFXCM
+{
+   IFXCM_DB        = 1,                // R/W Data Byte 4-7
+     IFXCM_DA        = 1<<1,   // R/W Data Byte 0-3
+     IFXCM_TRND      = 1<<2,   // Transmit Request (WRRD=1) or Reset New Date Bit (WRRD=0)
+     IFXCM_CLRINTPND = 1<<3,   // Clear Interrupt Pending Bit when reading the Message Object
+     IFXCM_CNTRL     = 1<<4,   // Access Interface X Message Control Bits
+     IFXCM_ARB       = 1<<5,   // Access Interface X Arbitration
+     IFXCM_MASK      = 1<<6,   // Access Interface X Mask Bits
+     IFXCM_WRRD      = 1<<7    // Read/Write (write data from Interface Registers to Message Object if ='1')
+     //            (read data from Message Object to Interface Registers if ='0')
+};
+
+/* Interface X Mask 2 Register */
+enum c_can_BASIC_IFXMSK2
+{
+   IFXMSK2_MDIR = 1<<14, // Mask Message Direction (message direction bit(RTR) used for acceptance filt. or not)
+     IFXMSK2_MXTD = 1<<15  // Mask Extended Identifier (extended id bit(IDE) used for acceptance filt. or not)
+};
+
+/* Interface X Arbitration 2 Register */
+enum c_can_BASIC_IFXARB2
+{
+   IFXARB2_DIR  = 1<<13,  // Message Direction (transmit='1')
+     IFXARB2_XTD  = 1<<14,  // Use Extended Identifier
+     IFXARB2_MVAL = 1<<15   // Message Validation
+};
+
+/* Interface X Message Control Register */
+enum c_can_BASIC_IFXMC
+{
+   IFXMC_EOB    = 1<<7,    // End of Buffer (marks last Message Object of FIFO Buffer)
+     IFXMC_TXRQST = 1<<8,    // Transmit Request
+     IFXMC_RMTEN  = 1<<9,    // Remote Enable
+     IFXMC_RXIE   = 1<<10,   // Receive Interrupt Enable
+     IFXMC_TXIE   = 1<<11,   // Transmit Interrupt Enable
+     IFXMC_UMASK  = 1<<12,   // Use Identifier Mask
+     IFXMC_INTPND = 1<<13,   // Interrupt Pending
+     IFXMC_MSGLST = 1<<14,   // Message Lost (Only valid for direction = receive)
+     IFXMC_NEWDAT = 1<<15    // New Data
+};
+
index 0dcac8c..7e02330 100644 (file)
@@ -48,6 +48,8 @@
 #define MSGOBJ_IRQ_REQUEST_b       3
 #define MSGOBJ_WORKER_WAKE_b       4
 #define MSGOBJ_FILTCH_REQUEST_b    5
+#define MSGOBJ_RX_MODE_b           6
+#define MSGOBJ_RX_MODE_EXT_b       7
 
 #define MSGOBJ_OPENED              (1<<MSGOBJ_OPENED_b)
 #define MSGOBJ_TX_REQUEST          (1<<MSGOBJ_TX_REQUEST_b)
@@ -55,6 +57,8 @@
 #define MSGOBJ_IRQ_REQUEST         (1<<MSGOBJ_IRQ_REQUEST_b)
 #define MSGOBJ_WORKER_WAKE         (1<<MSGOBJ_WORKER_WAKE_b)
 #define MSGOBJ_FILTCH_REQUEST      (1<<MSGOBJ_FILTCH_REQUEST_b)
+#define MSGOBJ_RX_MODE             (1<<MSGOBJ_RX_MODE_b)
+#define MSGOBJ_RX_MODE_EXT         (1<<MSGOBJ_RX_MODE_EXT_b)
 
 #define can_msgobj_test_fl(obj,obj_fl) \
   test_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
diff --git a/lincan/include/hms30c7202_can.h b/lincan/include/hms30c7202_can.h
new file mode 100644 (file)
index 0000000..25ce632
--- /dev/null
@@ -0,0 +1,28 @@
+/* hms30c7202_can.h - Hynix HMS30c7202 ARM device specific code\r
+ * Linux CAN-bus device driver.\r
+ * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de\r
+ * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl\r
+ * and Ake Hedman, eurosource, akhe@eurosource.se\r
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member\r
+ * email:pisa@cmp.felk.cvut.cz\r
+ * This software is released under the GPL-License.\r
+ * Version lincan-0.2  9 Jul 2003\r
+ */\r
+\r
+#ifndef __HMS30C7202_CAN__\r
+# define __HMS30C7202_CAN__\r
+\r
+int hms30c7202_init_hw_data(struct candevice_t *candev);\r
+int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr);\r
+int hms30c7202_request_io(struct candevice_t *candev);\r
+int hms30c7202_release_io(struct candevice_t *candev);\r
+int hms30c7202_reset(  struct candevice_t *candev);\r
+void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg);\r
+u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg);\r
+\r
+\r
+\r
+int hms30c7202_init_obj_data(struct chip_t *chip, int objnr);\r
+int hms30c7202_program_irq(struct candevice_t *candev);\r
+\r
+#endif /* __HMS30C7202_CAN__ */\r
index 65d6b2a..cc426b4 100644 (file)
@@ -209,6 +209,8 @@ struct chip_t {
  *     %MSGOBJ_TX_REQUEST .. the message object requests TX activation
  *     %MSGOBJ_TX_LOCK .. some IRQ routine or callback on some CPU 
  *             is running inside TX activation processing code
+ * @rx_preconfig_id: place to store RX message identifier for some chip types
+ *              that reuse same object for TX
  */
 struct msgobj_t {
        unsigned long obj_base_addr;
@@ -227,6 +229,8 @@ struct msgobj_t {
        struct canmsg_t rx_msg;
 
        struct chip_t *hostchip;
+       unsigned long rx_preconfig_id;
 
        atomic_t obj_used;
        struct list_head obj_users;
diff --git a/lincan/src/c_can.c b/lincan/src/c_can.c
new file mode 100644 (file)
index 0000000..6bef001
--- /dev/null
@@ -0,0 +1,944 @@
+/* c_can.c - Hynix HMS30c7202 ARM generic C_CAN module handling
+ * Linux CAN-bus device driver.
+ * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de
+ * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
+ * and Ake Hedman, eurosource, akhe@eurosource.se
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2  9 Jul 2003
+ */
+
+#define __NO_VERSION__
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/c_can.h"
+
+extern int stdmask;
+extern int extmask;
+
+can_spinlock_t c_can_spwlock=SPIN_LOCK_UNLOCKED; // Spin lock for write operations
+can_spinlock_t c_can_sprlock=SPIN_LOCK_UNLOCKED; // Spin lock for read operations
+can_spinlock_t c_can_if1lock=SPIN_LOCK_UNLOCKED; // spin lock for the if1 register
+can_spinlock_t c_can_if2lock=SPIN_LOCK_UNLOCKED; // spin lcok for the if2 register
+
+/**
+ * c_can_enable_configuration - enable chip configuration mode
+ * @pchip: pointer to chip state structure
+ */
+int c_can_enable_configuration(struct chip_t *pchip)
+{
+   int i=0;
+   u16 flags;
+   DEBUGMSG("(c%d)calling c_can_enable_configuration(...)\n", pchip->chip_nr);
+/*
+   DEBUGMSG("Trying disable_irq(...) : ");
+   //disable IRQ
+       disable_irq(chip->chip_irq);
+*/
+   //read Control Register
+   flags=c_can_read_reg_w(pchip, CCCR);
+   //set Init-Bit in the Control Register (10 tries)
+   while ((!(flags & CR_INIT)) && (i<=10))
+     {
+       c_can_write_reg_w(pchip,flags|CR_INIT, CCCR);
+       udelay(1000);
+       i++;
+       flags=c_can_read_reg_w(pchip, CCCR);
+     }
+   if (i>=10)
+     {
+       CANMSG("Reset error\n");
+       //enable_irq(chip->chip_irq);
+       return -ENODEV;
+     }
+
+   DEBUGMSG("-> ok\n");
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_disable_configuration(struct chip_t *pchip)
+{
+   int i=0;
+   u16 flags;
+
+   DEBUGMSG("(c%d)calling c_can_disable_configuration(...)\n", pchip->chip_nr);
+   //read Control Register
+   flags=c_can_read_reg_w(pchip, CCCR);
+
+   //reset Init-Bit in the Control Register (10 tries)
+   while ( (flags & CR_INIT) && (i<=10) )
+     {
+       c_can_write_reg_w( pchip,flags & ~CR_INIT, CCCR);
+       udelay(1000); //100 microseconds
+       i++;
+       flags=c_can_read_reg_w(pchip, CCCR);
+     }
+   if (i>=10)
+     {
+       CANMSG("Error leaving reset status\n");
+       return -ENODEV;
+     }
+
+   //enable IRQ
+   //enable_irq(chip->chip_irq);
+   DEBUGMSG("-> ok\n");
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_chip_config(struct chip_t *pchip)
+{
+
+   DEBUGMSG("(c%d)calling c_can_chip_config(...)\n", pchip->chip_nr);
+   // Validate pointer
+   if ( NULL == pchip ) return -1;
+
+   if (pchip->baudrate == 0)
+     pchip->baudrate=1000;
+
+   if (c_can_baud_rate(pchip,pchip->baudrate*1000,pchip->clock,0,75,0))
+     {
+       CANMSG("Error configuring baud rate\n");
+       return -ENODEV;
+     }
+       /*if (extended){
+          if (c_can_extended_mask(pchip,0x0000000,extmask)) {
+                  CANMSG("Error configuring extended mask\n");
+                  return -ENODEV;
+      }
+   }else{
+      if (c_can_standard_mask(pchip,0x0000,stdmask)) {
+                  CANMSG("Error configuring standard mask\n");
+                  return -ENODEV;
+          }
+       }*/
+   if (c_can_clear_objects(pchip))
+     {
+       CANMSG("Error clearing message objects\n");
+       return -ENODEV;
+     }
+   if (c_can_config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE))
+     {
+       CANMSG("Error configuring interrupts\n");
+       return -ENODEV;
+     }
+
+   DEBUGMSG("-> Configured successfully\n");
+
+#ifdef REGDUMP
+   c_can_registerdump(pchip);
+#endif
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+ * Checks if the Busy-Bit in the IF1-Command-Request Register is set
+ */
+int c_can_if1_busycheck(struct chip_t *pchip)
+{
+
+   int i=0;
+   unsigned short comreg = 0;
+
+   comreg = c_can_read_reg_w( pchip, CCIF1CR);
+   while ( (comreg & IFXCR_BUSY) && (i<=10) )
+     {
+       udelay(100); //100 microseconds
+       i++;
+       comreg=c_can_read_reg_w( pchip, CCIF1CR);
+     }
+   if (i>=10)
+     {
+       CANMSG("Error Busy-Bit stays set\n");
+       return -ENODEV;
+     }
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+ * Checks if the Busy-Bit in the IF2-Command-Request Register is set
+ */
+int c_can_if2_busycheck(struct chip_t *pchip)
+{
+
+   int i=0;
+   unsigned short comreg = 0;
+
+   comreg = c_can_read_reg_w( pchip, CCIF2CR);
+   while ( (comreg & IFXCR_BUSY) && (i<=10) )
+     {
+       udelay(100); //100 microseconds
+       i++;
+       comreg=c_can_read_reg_w( pchip, CCIF2CR);
+     }
+   if (i>=10)
+     {
+       CANMSG("Error Busy-Bit stays set\n");
+       return -ENODEV;
+     }
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+ * Though the C-CAN Chip can handle one mask for each Message Object, this Method defines
+ * one mask for all MOs. That means every MO gets the same mask.
+ */
+
+/* Set communication parameters.
+ * param rate baud rate in Hz
+ * param clock frequency of C-CAN clock in Hz
+ * param sjw synchronization jump width (0-3) prescaled clock cycles
+ * param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio
+ * param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP
+ */
+int c_can_baud_rate(struct chip_t *pchip, int rate, int clock,
+                       int sjw, int sampl_pt, int flags)
+{
+   int best_error = 1000000000, error;
+   int best_tseg=0, best_brp=0, best_rate=0, brp=0;
+   int tseg=0, tseg1=0, tseg2=0;
+
+   unsigned short tempCR = 0;
+
+   DEBUGMSG("(c%d)calling c_can_baud_rate(...)\n", pchip->chip_nr);
+
+   if (c_can_enable_configuration(pchip))
+     return -ENODEV;
+
+   clock /=2;
+
+       /* tseg even = round down, odd = round up */
+   for (tseg=(0+0+2)*2; tseg<=(MAX_TSEG2+MAX_TSEG1+2)*2+1; tseg++)
+     {
+       brp = clock/((1+tseg/2)*rate)+tseg%2;
+       if (brp == 0 || brp > 64)
+         continue;
+       error = rate - clock/(brp*(1+tseg/2));
+       if (error < 0)
+         error = -error;
+       if (error <= best_error)
+         {
+            best_error = error;
+            best_tseg = tseg/2;
+            best_brp = brp-1;
+            best_rate = clock/(brp*(1+tseg/2));
+         }
+     }
+   if (best_error && (rate/best_error < 10))
+     {
+       CANMSG("baud rate %d is not possible with %d Hz clock\n",
+              rate, 2*clock);
+       CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n",
+              best_rate, best_brp, best_tseg, tseg1, tseg2);
+       return -EINVAL;
+     }
+   tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100;
+   if (tseg2 < 0)
+     tseg2 = 0;
+   if (tseg2 > MAX_TSEG2)
+     tseg2 = MAX_TSEG2;
+   tseg1 = best_tseg-tseg2-2;
+   if (tseg1 > MAX_TSEG1)
+     {
+       tseg1 = MAX_TSEG1;
+       tseg2 = best_tseg-tseg1-2;
+     }
+
+   DEBUGMSG("-> Setting %d bps.\n", best_rate);
+   DEBUGMSG("->brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n",
+           best_brp, best_tseg, tseg1, tseg2,
+           (100*(best_tseg-tseg2)/(best_tseg+1)));
+
+   //read Control Register
+   tempCR = c_can_read_reg_w( pchip, CCCR);
+   //Configuration Change Enable
+   c_can_write_reg_w(pchip, tempCR | CR_CCE, CCCR);
+   c_can_write_reg_w(pchip, ((unsigned short)tseg2)<<12 | ((unsigned short)tseg1)<<8
+                        | (unsigned short)sjw<<6 | (unsigned short) best_brp,
+                        CCBT);
+
+   if (c_can_disable_configuration(pchip))
+     return -ENODEV;
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_mask(struct msgobj_t *pmsgobj,
+               u32 mask,
+              u16 usedirbit)
+{
+   unsigned short tempreg = 0;
+   unsigned short readMaskCM;
+   unsigned short writeMaskCM;
+
+   DEBUGMSG("(c%dm%d)calling c_can_mask(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object);
+
+   readMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_MASK;
+   writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_MASK | IFXCM_WRRD;
+
+   spin_lock( &c_can_if1lock );
+
+   //load Message Object in IF1
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   //setting Message Valid Bit to zero
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, tempreg & ~(IFXARB2_MVAL), CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   //setting UMask, MsgVal and Mask Register
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+
+   //writing acceptance mask for extended or standart mode
+   if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT))
+     {
+       if (usedirbit)
+         c_can_write_reg_w(pmsgobj->hostchip, 
+                           (mask>>16 & 0x1FFF) | IFXMSK2_MXTD | IFXMSK2_MDIR, CCIF1M2);
+       else
+         c_can_write_reg_w(pmsgobj->hostchip, 
+                           (mask>>16 & 0x1FFF) | IFXMSK2_MXTD, CCIF1M2);
+       c_can_write_reg_w(pmsgobj->hostchip, (mask & 0xFFFF), CCIF1M1);
+     }
+   else
+     {
+       if (usedirbit)
+         c_can_write_reg_w(pmsgobj->hostchip, 
+                           ((mask<<2) & 0x1FFC) | IFXMSK2_MDIR, CCIF1M2);
+       else
+         c_can_write_reg_w(pmsgobj->hostchip,
+                           ((mask<<2) & 0x1FFC), CCIF1M2);
+       c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1M1);
+     }
+   //seting Message Valid Bit to one
+   tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, tempreg | IFXARB2_MVAL, CCIF1A2);
+   //write to chip
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   spin_unlock( &c_can_if1lock );
+
+   DEBUGMSG("-> Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
+
+#ifdef REGDUMP
+   c_can_registerdump(pmsgobj->hostchip);
+#endif
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_use_mask(struct msgobj_t *pmsgobj,
+                  u16 useflag)
+{
+   unsigned short tempreg = 0;
+   unsigned short readMaskCM;
+   unsigned short writeMaskCM;
+
+#ifdef DEBUG
+   char *boolstring = "false";
+   if (useflag) boolstring = "true";
+#endif
+   DEBUGMSG("(c%dm%d)calling c_can_use_mask(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object);
+
+   readMaskCM = IFXCM_CNTRL | IFXCM_ARB;
+   writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_WRRD;;
+
+   spin_lock( &c_can_if1lock );
+
+   //load Message Object in IF1
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   //setting Message Valid Bit to zero
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, tempreg & ~IFXARB2_MVAL, CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   //setting UMask bit
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   if ( useflag )
+     {
+       tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1DMC);
+       c_can_write_reg_w(pmsgobj->hostchip, tempreg | IFXMC_UMASK, CCIF1DMC);
+     }
+   else
+     {
+       tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1DMC);
+       c_can_write_reg_w(pmsgobj->hostchip, tempreg & ~IFXMC_UMASK, CCIF1DMC);
+     }
+   //seting Message Valid Bit to one
+   tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, tempreg | IFXARB2_MVAL, CCIF1A2);
+   //write to chip
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   spin_unlock( &c_can_if1lock );
+
+#ifdef DEBUG
+   DEBUGMSG("-> Setting umask bit to %s\n",boolstring);
+#endif
+#ifdef REGDUMP
+   c_can_registerdump(pmsgobj->hostchip);
+#endif
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_clear_objects(struct chip_t *pchip)
+{
+   unsigned short i = 0;
+   unsigned short tempreg = 0;
+
+   unsigned short maskCM = IFXCM_ARB;
+
+   DEBUGMSG("(c%d)calling c_can_clear_objects(...)\n", pchip->chip_nr);
+
+   spin_lock( &c_can_if1lock );
+   spin_lock( &c_can_if2lock );
+
+   for (i=0; i<0x10; i++)
+     {
+
+       //loading Message Objects in IF1 and IF2
+       if (c_can_if1_busycheck(pchip)) return -ENODEV;
+       c_can_write_reg_w(pchip, maskCM, CCIF1CM);
+       c_can_write_reg_w(pchip, i, CCIF1CR);
+       if (c_can_if2_busycheck(pchip)) return -ENODEV;
+       c_can_write_reg_w(pchip, maskCM, CCIF2CM);
+       c_can_write_reg_w(pchip, i+0x10, CCIF2CR);
+
+       //setting Message Valid Bit to zero
+       if (c_can_if1_busycheck(pchip)) return -ENODEV;
+       tempreg = c_can_read_reg_w(pchip, CCIF1A2);
+       c_can_write_reg_w(pchip, tempreg & ~IFXARB2_MVAL, CCIF1A2);
+       c_can_write_reg_w(pchip, i, CCIF1CR);
+       if (c_can_if2_busycheck(pchip)) return -ENODEV;
+       tempreg = c_can_read_reg_w(pchip, CCIF2A2);
+       c_can_write_reg_w(pchip, tempreg & ~IFXARB2_MVAL, CCIF2A2);
+       c_can_write_reg_w(pchip, i+0x10, CCIF2CR);
+     }
+
+   for (i=0; i<pchip->max_objects; i++)
+     {
+       if (can_msgobj_test_fl(pchip->msgobj[i],OPENED))
+         {
+            // In- and output buffer re-initialization
+            canqueue_ends_flush_inlist(pchip->msgobj[i]->qends);
+            canqueue_ends_flush_outlist(pchip->msgobj[i]->qends);
+
+         }
+     }
+
+   spin_unlock( &c_can_if1lock );
+   spin_unlock( &c_can_if2lock );
+
+   DEBUGMSG("-> Message Objects reset\n");
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_config_irqs(struct chip_t *pchip,
+                      u16 irqs)
+{
+   u16 tempreg;
+
+   DEBUGMSG("(c%d)calling c_can_config_irqs(...)\n", pchip->chip_nr);
+
+   /*
+    CANMSG("c_can_config_irqs not implemented\n");
+    return -ENOSYS;
+    */
+
+   tempreg = c_can_read_reg_w(pchip, CCCR);
+   //DEBUGMSG("-> CAN Control Register: 0x%.4lx\n",(long)tempreg);
+   c_can_write_reg_w(pchip, tempreg | (irqs & 0xe), CCCR);
+   DEBUGMSG("-> Configured hardware interrupt delivery\n");
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_pre_read_config(struct chip_t *pchip, struct msgobj_t *pmsgobj)
+{
+   unsigned short readMaskCM = IFXCM_CNTRL | IFXCM_ARB;
+   unsigned short writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_WRRD;
+   unsigned short mcreg = 0;
+   u32 id=pmsgobj->rx_preconfig_id;
+
+   DEBUGMSG("(c%dm%d)calling c_can_pre_read_config(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object);
+
+   spin_lock( &c_can_if1lock );
+
+
+   //loading Message Object in IF1
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+   //setting Message Valid Bit to zero
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1A2);
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+   //Configuring Message-Object
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   mcreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, 
+                     ((mcreg & IFXMC_UMASK) | IFXMC_EOB | IFXMC_RXIE), CCIF1DMC);
+   //writing arbitration mask for extended or standart mode
+   if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT))
+     {
+       c_can_write_reg_w(pmsgobj->hostchip, 
+                         IFXARB2_XTD | IFXARB2_MVAL | (id>>16 & 0x1FFF), CCIF1A2);
+       c_can_write_reg_w(pmsgobj->hostchip, id & 0xFFFF, CCIF1A1);
+     }
+   else
+     {
+       c_can_write_reg_w(pmsgobj->hostchip, 
+                         IFXARB2_MVAL | (id<<2 & 0x1FFC), CCIF1A2);
+       //c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1A1);
+     }
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   spin_unlock( &c_can_if1lock );
+
+   DEBUGMSG("-> Receiving through message object %d with id=%d\n", pmsgobj->object,
+           id);
+#ifdef REGDUMP
+   c_can_registerdump(pmsgobj->hostchip);
+#endif
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, 
+                               struct canmsg_t *msg)
+{
+       return 0; 
+}
+
+ ///////////////////////////////////////////////////////////////////////
+/*
+ *Prepare the Chip to send specified Message over specified Messageobject
+ *In this version the method also sends the message.
+ */
+
+int c_can_send_msg(struct chip_t *pchip, struct msgobj_t *pmsgobj,
+                       struct canmsg_t *pmsg)
+{   
+   unsigned short readMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_DA | IFXCM_DB;
+   unsigned short writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_DA | IFXCM_DB| IFXCM_WRRD;
+   unsigned short writeSendMskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_DA | IFXCM_DB| IFXCM_WRRD | IFXCM_TRND;
+   unsigned short mcreg = 0;
+   //unsigned short arbreg = 0;
+   unsigned short dataA1 = 0;
+   unsigned short dataA2 = 0;
+   unsigned short dataB1 = 0;
+   unsigned short dataB2 = 0;
+
+   DEBUGMSG("(c%dm%d)calling c_can_send_msg(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object);
+
+   spin_lock( &c_can_if2lock );
+
+   can_msgobj_clear_fl(pmsgobj,RX_MODE);
+   
+   //loading Message Object in IF1
+   if (c_can_if2_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF2CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF2CR);
+   //setting Message Valid Bit to zero
+   if (c_can_if2_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF2A2);
+   c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF2CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF2CR);
+   //Configuring MO
+   if (c_can_if2_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   mcreg = c_can_read_reg_w( pmsgobj->hostchip, CCIF2CM);
+   //remote enable?
+   //define Command Mask
+   c_can_write_reg_w(pmsgobj->hostchip, (mcreg & IFXMC_UMASK) | IFXMC_EOB | IFXMC_TXIE
+                    | IFXMC_RMTEN | IFXMC_NEWDAT | IFXMC_TXRQST | (pmsg->length & 0xF), CCIF2DMC);
+   //set Arbitration Bits
+   if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT))
+     {
+       c_can_write_reg_w(pmsgobj->hostchip, (u16)(pmsg->id), CCIF2A1);
+       c_can_write_reg_w(pmsgobj->hostchip, IFXARB2_XTD | IFXARB2_MVAL | IFXARB2_DIR
+                                           | ((u16)(pmsg->id>>16) & 0x1FFF), CCIF2A2);
+     }
+   else
+     {
+       c_can_write_reg_w(pmsgobj->hostchip, 
+                         (IFXARB2_MVAL | IFXARB2_DIR | ((u16)(pmsg->id<<2) & 0x1FFC)), CCIF2A2);
+       c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1A1);
+     }
+   //write Data
+   if (pmsg->length>0)
+     {
+       dataA1 = pmsg->data[0] | (u16)pmsg->data[1]<<8;
+       dataA2 = pmsg->data[2] | (u16)pmsg->data[3]<<8;
+       dataB1 = pmsg->data[4] | (u16)pmsg->data[5]<<8;
+       dataB2 = pmsg->data[6] | (u16)pmsg->data[7]<<8;
+
+       c_can_write_reg_w(pmsgobj->hostchip, dataA1, CCIF2DA1);
+       c_can_write_reg_w(pmsgobj->hostchip, dataA2, CCIF2DA2);
+       c_can_write_reg_w(pmsgobj->hostchip, dataB1, CCIF2DB1);
+       c_can_write_reg_w(pmsgobj->hostchip, dataB2, CCIF2DB2);
+     }
+
+   c_can_write_reg_w(pmsgobj->hostchip, writeSendMskCM, CCIF2CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF2CR);
+
+   spin_unlock( &c_can_if2lock );
+
+   DEBUGMSG("-> ok\n");
+#ifdef REGDUMP
+   c_can_registerdump(pmsgobj->hostchip);
+#endif
+
+   return 0;
+}
+
+//////////////////////////////////////////////////////////////////////
+int c_can_remote_request(struct chip_t *pchip, struct msgobj_t *pmsgobj )
+{
+   unsigned short readMaskCM = IFXCM_CNTRL;// | IFXCM_ARB;
+   //unsigned short writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_WRRD;
+   unsigned short mcreg = 0;
+
+   DEBUGMSG("(c%dm%d)calling c_can_remote_request(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object);
+
+   //Remote request is only available when the message object is in receiving mode
+   if (!can_msgobj_test_fl(pmsgobj,RX_MODE))
+     {
+       return 1;
+     }
+
+   spin_lock( &c_can_if1lock );
+
+   //loading Message Object in IF1
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM);
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+   //setting Transmit-Request-Bit
+   if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV;
+   mcreg = c_can_read_reg_w( pmsgobj->hostchip, CCIF1DMC);
+   c_can_write_reg_w(pmsgobj->hostchip, mcreg | IFXMC_TXRQST, CCIF1DMC);
+
+   c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR);
+
+   spin_unlock( &c_can_if1lock );
+
+   DEBUGMSG("-> Sent remote request through message object %d\n", pmsgobj->object);
+#ifdef REGDUMP
+   c_can_registerdump(pmsgobj->hostchip);
+#endif
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_set_btregs(struct chip_t *pchip,
+                     u16 btr0,
+                    u16 btr1)
+{
+   unsigned short tempCR = 0;
+
+   DEBUGMSG("(c%d)calling c_can_set_btregs(...)\n", pchip->chip_nr);
+
+   // Validate pointer
+   if ( NULL == pchip ) return -1;
+
+   if (c_can_enable_configuration(pchip))
+     return -ENODEV;
+
+   //read Control Register
+   tempCR = c_can_read_reg_w(pchip, CCCR);
+   //Configuration Change Enable
+   c_can_write_reg_w(pchip, tempCR | CR_CCE, CCCR);
+   c_can_write_reg_w(pchip, btr0 | (btr1<<8), CCBT);
+
+   if (c_can_disable_configuration(pchip))
+     return -ENODEV;
+
+   DEBUGMSG("-> ok\n");
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+ * Starts the Chip, by setting the CAN Enable Bit
+ */
+int c_can_start_chip(struct chip_t *pchip)
+{
+   u16 flags = 0;
+
+   DEBUGMSG("(c%d)calling c_can_start_chip(...)\n", pchip->chip_nr);
+
+   // Validate pointer
+   if ( NULL == pchip )
+     {
+       DEBUGMSG("-> Error Chip not available.\n");
+       return -1;
+     }
+
+   //   flags = c_can_read_reg_w(pchip, CCCE) | CE_EN;
+   //   c_can_write_reg_w(pchip, flags, CCCE);
+   //
+   flags = c_can_read_reg_w(pchip, CCCE) | CE_EN;
+   c_can_write_reg_w(pchip, flags, CCCE);
+
+   DEBUGMSG("-> ok\n");
+#ifdef REGDUMP
+   c_can_registerdump(pchip);
+#endif
+
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+ * Stops the Chip, by deleting the CAN Enable Bit
+ */
+int c_can_stop_chip(struct chip_t *pchip)
+{
+   u16 flags = 0;
+
+   DEBUGMSG("(c%d)calling c_can_stop_chip(...)\n", pchip->chip_nr);
+
+   // Validate pointer
+   if ( NULL == pchip )
+     {
+       DEBUGMSG("-> Error Chip not available.\n");
+       return -1;
+     }
+
+   flags = c_can_read_reg_w(pchip, CCCE) & ~CE_EN;
+   c_can_write_reg_w(pchip, flags, CCCE);
+
+   DEBUGMSG("-> ok\n");
+   return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+ *Check the TxOK bit of the Status Register and resets it afterwards.
+ */
+int c_can_check_tx_stat(struct chip_t *pchip)
+{
+   unsigned long tempstat = 0;
+
+   DEBUGMSG("(c%d)calling c_can_check_tx_stat(...)\n", pchip->chip_nr);
+
+   // Validate pointer
+   if ( NULL == pchip ) return -1;
+
+   tempstat = c_can_read_reg_w(pchip, CCSR);
+
+   if (tempstat & SR_TXOK)
+     {
+       c_can_write_reg_w(pchip, tempstat & ~SR_TXOK, CCSR);
+       return 0;
+     }
+   else
+     {
+       return 1;
+     }
+}
+
+
+///////////////////////////////////////////////////////////////////////
+int c_can_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
+{
+       can_preempt_disable();
+       
+       can_msgobj_set_fl(obj,TX_REQUEST);
+
+       /* calls i82527_irq_write_handler synchronized with other invocations
+         from kernel and IRQ context */
+       c_can_irq_sync_activities(chip, obj);
+
+       can_preempt_enable();
+       return 0;
+}
+
+///////////////////////////////////////////////////////////////////////
+int c_can_filtch_rq(struct chip_t *chip, struct msgobj_t *obj)
+{
+       can_preempt_disable();
+       
+       can_msgobj_set_fl(obj,FILTCH_REQUEST);
+
+       /* setups filter synchronized with other invocations from kernel and IRQ context */
+       c_can_irq_sync_activities(chip, obj);
+
+       can_preempt_enable();
+       return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+void c_can_registerdump(struct chip_t *pchip)
+{
+   CANMSG("------------------------------------\n");
+   CANMSG("---------C-CAN Register Dump--------\n");
+   CANMSG("------------at 0x%.8lx-----------\n"
+         ,(unsigned long)pchip->chip_base_addr);
+   CANMSG("Control Register:             0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCCR)));
+   CANMSG("Status Register:              0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCSR)));
+   CANMSG("Error Counting Register:      0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCEC)));
+   CANMSG("Bit Timing Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCBT)));
+   CANMSG("Interrupt Register:           0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCINTR)));
+   CANMSG("Test Register:                0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCTR)));
+   CANMSG("Baud Rate Presc. Register:    0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCBRPE)));
+   CANMSG("CAN Enable Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCCE)));
+   CANMSG("Transm. Req. 1 Register:      0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCTREQ1)));
+   CANMSG("Transm. Req. 2 Register:      0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCTREQ2)));
+   CANMSG("New Data 1 Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCND1)));
+   CANMSG("New Data 2 Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCND2)));
+   CANMSG("Interrupt Pend. 1 Register:   0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCINTP1)));
+   CANMSG("Interrupt Pend. 2 Register:   0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCINTP2)));
+   CANMSG("------------------------------------\n");
+   CANMSG("IF1 Command Req. Register:    0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1CR)));
+   CANMSG("IF1 Command Mask Register:    0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1CM)));
+   CANMSG("IF1 Mask 1 Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1M1)));
+   CANMSG("IF1 Mask 2 Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1M2)));
+   CANMSG("IF1 Arbitration 1 Register:   0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1A1)));
+   CANMSG("IF1 Arbitration 2 Register:   0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1A2)));
+   CANMSG("IF1 Message Control Register: 0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1DMC)));
+   CANMSG("IF1 Data A1 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1DA1)));
+   CANMSG("IF1 Data A2 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1DA2)));
+   CANMSG("IF1 Data B1 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1DB1)));
+   CANMSG("IF1 Data B2 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF1DB2)));
+   CANMSG("------------------------------------\n");
+   CANMSG("IF2 Command Req. Register:    0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2CR)));
+   CANMSG("IF2 Command Mask Register:    0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2CM)));
+   CANMSG("IF2 Mask 1 Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2M1)));
+   CANMSG("IF2 Mask 2 Register:          0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2M2)));
+   CANMSG("IF2 Arbitration 1 Register:   0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2A1)));
+   CANMSG("IF2 Arbitration 2 Register:   0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2A2)));
+   CANMSG("IF2 Message Control Register: 0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2DMC)));
+   CANMSG("IF2 Data A1 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2DA1)));
+   CANMSG("IF2 Data A2 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2DA2)));
+   CANMSG("IF2 Data B1 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2DB1)));
+   CANMSG("IF2 Data B2 Register:         0x%.4lx\n",
+         (long)(c_can_read_reg_w( pchip, CCIF2DB2)));
+   CANMSG("------------------------------------\n");
+   CANMSG("------------------------------------\n");
+}
+
+///////////////////////////////////////////////////////////////////////
+
+int c_can_register(struct chipspecops_t *chipspecops)
+{
+       CANMSG("initializing c_can chip operations\n");
+       chipspecops->chip_config=c_can_chip_config;
+       chipspecops->baud_rate=c_can_baud_rate;
+       /*chipspecops->standard_mask=c_can_standard_mask;
+       chipspecops->extended_mask=c_can_extended_mask;
+       chipspecops->message15_mask=c_can_extended_mask;*/
+       chipspecops->clear_objects=c_can_clear_objects;
+       /*chipspecops->config_irqs=c_can_config_irqs;*/
+       chipspecops->pre_read_config=c_can_pre_read_config;
+       chipspecops->pre_write_config=c_can_pre_write_config;
+       chipspecops->send_msg=c_can_send_msg;
+       chipspecops->check_tx_stat=c_can_check_tx_stat;
+       chipspecops->wakeup_tx=c_can_wakeup_tx;
+       chipspecops->filtch_rq = c_can_filtch_rq;
+       chipspecops->remote_request=c_can_remote_request;
+       chipspecops->enable_configuration=c_can_enable_configuration;
+       chipspecops->disable_configuration=c_can_disable_configuration;
+       chipspecops->set_btregs=c_can_set_btregs;
+       chipspecops->start_chip=c_can_start_chip;
+       chipspecops->stop_chip=c_can_stop_chip;
+       chipspecops->irq_handler=c_can_irq_handler;
+       return 0;
+}
+
+/*int c_can_register(struct chip_t *pchip)
+{
+   DEBUGMSG("(c%d)call c_can_register\n", pchip->chip_nr);
+
+   // Validate pointer
+   if ( NULL == pchip ) return -1;
+
+   pchip->chip_config = c_can_chip_config;
+   pchip->set_baud_rate = c_can_baud_rate;
+   pchip->set_mask = c_can_mask;
+   pchip->set_use_mask = c_can_use_mask;
+   //pchip->set_message15_mask = c_can_extended_mask;
+   pchip->clear_objects = c_can_clear_objects;
+   pchip->config_irqs = c_can_config_irqs;
+   pchip->pre_read_config = c_can_pre_read_config;
+   //pchip->pre_write_config = c_can_pre_write_config;
+   pchip->send_msg = c_can_send_msg;
+   pchip->check_tx_stat = c_can_check_tx_stat;
+   pchip->remote_request = c_can_remote_request;
+   pchip->enable_configuration = c_can_enable_configuration;
+   pchip->disable_configuration = c_can_disable_configuration;
+   pchip->set_btregs = c_can_set_btregs;
+   pchip->start_chip = c_can_start_chip;
+   pchip->stop_chip = c_can_stop_chip;
+   pchip->register_dump = c_can_registerdump;
+
+   DEBUGMSG("-> ok\n");
+   return 0;
+}
+*/
diff --git a/lincan/src/c_can_irq.c b/lincan/src/c_can_irq.c
new file mode 100644 (file)
index 0000000..5257d0f
--- /dev/null
@@ -0,0 +1,510 @@
+/* c_can_irq.c - Hynix HMS30c7202 ARM IRQ handling code
+ * Linux CAN-bus device driver.
+ * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de
+ * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
+ * and Ake Hedman, eurosource, akhe@eurosource.se
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2  9 Jul 2003
+ */
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/c_can.h"
+
+union c_can_data
+{
+   unsigned short wdata[4];
+   unsigned char bdata[8];
+};
+
+
+
+// prototypes
+inline void c_can_irq_read_handler( struct chip_t *pchip, int idxobj, u32 msgid  );
+
+inline void c_can_irq_write_handler( struct chip_t *pchip, int idxobj);
+
+void c_can_irq_rtr_handler( struct chip_t *pchip, int idxobj, u32 msgid );
+
+u16 readMaskCM = IFXCM_ARB | IFXCM_CNTRL | IFXCM_CLRINTPND
+  | IFXCM_TRND | IFXCM_DA | IFXCM_DB;
+
+u16 msgLstReadMaskCM = IFXCM_CNTRL;
+u16 msgLstWriteMaskCM =  IFXCM_CNTRL | IFXCM_WRRD;
+
+///////////////////////////////////////////////////////////////////////////////
+// c_can_irq_write_handler
+//
+// Send a message from the output fifo ( if any ).
+//
+
+inline void c_can_irq_write_handler( struct chip_t *pchip, int idxobj)
+{
+       int cmd;
+       struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
+
+       DEBUGMSG("(c%dm%d)calling c_can_irq_write_handler(...)\n",
+               pchip->chip_idx, pmsgobj->object);
+
+       if(pmsgobj->tx_slot){
+               /* Do local transmitted message distribution if enabled */
+               if (processlocal){
+                       pmsgobj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->tx_slot->msg);
+               }
+               /* Free transmitted slot */
+               canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot);
+               pmsgobj->tx_slot=NULL;
+       }
+   
+       // Get ready to send next message
+       spin_lock( &c_can_spwlock );
+
+       cmd=canque_test_outslot(pmsgobj->qends, &pmsgobj->tx_qedge, &pmsgobj->tx_slot);
+       if(cmd<0){
+               DEBUGMSG("(c%dm%d)Nothin to write\n",
+                       pchip->chip_idx, pmsgobj->object);
+               spin_unlock( &c_can_spwlock );
+               return;
+       }
+
+       // Send the message
+       if ( pchip->chipspecops->send_msg( pchip, pmsgobj,&pmsgobj->tx_slot->msg) ) {
+               pmsgobj->ret = -1;
+               canque_notify_inends(pmsgobj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
+               canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot);
+               pmsgobj->tx_slot=NULL;
+               spin_unlock( &c_can_spwlock );
+               DEBUGMSG("(c%dm%d)c_can_irq_handler: Unable to send message\n",
+                       pchip->chip_idx, pmsgobj->object );
+               return;
+       } else {
+               // Another message sent
+           #ifdef CAN_WITH_STATISTICS
+               pchip->stat.cntTxPkt++;
+               pchip->stat.cntTxData += pmsgobj->tx_slot->length;
+           #endif /*CAN_WITH_STATISTICS*/
+       }
+       spin_unlock( &c_can_spwlock );
+
+       // Wake up any waiting writer
+       return;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// c_can_irq_read_handler
+//
+// Message received form the line. Write it in the input fifo->
+//
+
+inline void c_can_irq_read_handler( struct chip_t *pchip,
+                                   int idxobj, u32 msgid  )
+{
+       int i=0;
+       u16 bDataAvail=1 ;
+       u16 msgCntlReg = 0;
+       union c_can_data readData;
+       struct msgobj_t *pmsgobj = pchip->msgobj[idxobj];
+               
+       DEBUGMSG("(c%dm%d)calling c_can_irq_read_handler(...)\n",
+               pchip->chip_idx, pmsgobj->object);
+       
+       while ( bDataAvail ) {
+            
+           #ifdef CAN_WITH_STATISTICS
+               pchip->stat.cntRxFifoOvr++;
+           #endif /*CAN_WITH_STATISTICS*/
+               // Message length
+               msgCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
+       
+               pmsgobj->rx_msg.length = msgCntlReg & 0x000F;
+       
+               // Message id
+               pmsgobj->rx_msg.id = (u32)msgid;
+       
+               // Fetch message bytes
+               if (pmsgobj->rx_msg.length > 0)
+                       readData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
+               if (pmsgobj->rx_msg.length > 2)
+                       readData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
+               if (pmsgobj->rx_msg.length > 4)
+                       readData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
+               if (pmsgobj->rx_msg.length > 6)
+                       readData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
+               
+               for ( i=0; i < pmsgobj->rx_msg.length; i++ ) {
+                       pmsgobj->rx_msg.data[ i ] = readData.bdata[i];
+               }
+               DEBUGMSG("(c%dm%d)Received Message:\n",
+                     pchip->chip_idx, pmsgobj->object);
+               DEBUGMSG(" id = %d\n",
+                     pmsgobj->rx_msg.id);
+               DEBUGMSG(" length = %d\n",
+                     pmsgobj->rx_msg.length);
+               for ( i=0; i < pmsgobj->rx_msg.length; i++ )
+                       DEBUGMSG(" data[%d] = 0x%.2x\n", i, pmsgobj->rx_msg.data[i]);
+               
+               canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->rx_msg);
+           
+           #ifdef CAN_WITH_STATISTICS
+               // Another received packet
+               pchip->stat.cntRxPkt++;
+
+               // Add databytes read to statistics block
+               pchip->stat.cntRxData += pmsgobj->rx_msg.length;
+           #endif /*CAN_WITH_STATISTICS*/
+
+               spin_unlock( &c_can_sprlock );
+
+               // Check if new data arrived
+               if (c_can_if1_busycheck(pchip)) ;
+               c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
+               c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
+               if (c_can_if1_busycheck(pchip)) ;
+               if ( !( ( bDataAvail = c_can_read_reg_w( pchip, CCIF1DMC ) ) &
+                       IFXMC_NEWDAT ) ) {
+                       break;
+               }
+
+               if ( bDataAvail & IFXMC_MSGLST ) {
+                       CANMSG("(c%dm%d)c-can fifo full: Message lost!\n",
+                       pchip->chip_idx, pmsgobj->object);
+               }
+
+       }
+       // while
+}
+
+void c_can_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj)
+{
+       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) {
+
+               /*if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) {
+                       if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
+                               i82527_irq_write_handler(chip, obj);
+               }
+
+               if(!obj->tx_slot) {
+                       if(can_msgobj_test_and_clear_fl(obj,FILTCH_REQUEST)) {
+                               i82527_irq_update_filter(chip, obj);
+                       }
+               }*/
+               /* FIXME: these functionality has to be implemented to start TX */
+
+               can_msgobj_clear_fl(obj,TX_LOCK);
+               if(can_msgobj_test_fl(obj,TX_REQUEST))
+                       continue;
+               if(can_msgobj_test_fl(obj,FILTCH_REQUEST) && !obj->tx_slot)
+                       continue;
+               break;
+       }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// c_can_irq_handler
+//
+
+can_irqreturn_t c_can_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct rtr_id *rtr_search = hardware_p->rtr_queue;
+       struct chip_t *pchip = (struct chip_t *)dev_id;
+       u16 chip_status;
+       int id0=0, id1=0;
+       u16 errcount = 0;
+       u16 irqreg = 0;
+       u32 msgid = 0;
+       u16 tempCntlReg = 0;
+       //#ifdef CAN_DEBUG
+       // u32 intCntrVAddr = 0;
+       //#endif
+       //unsigned short flags = 0;
+
+       //if (pchip->ntype != CAN_CHIPTYPE_C_CAN)       {
+       //      DEBUGMSG("\n(c%d)IRQ not for c_can_irq_handler(...)\n", pchip->chip_idx);
+       //      return;
+       //}
+
+       irqreg = c_can_read_reg_w( pchip, CCINTR );
+
+       if(!irqreg) {
+               DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx spurious interrupt\n",
+                       pchip->chip_idx,
+                       (long)( pchip->/*v*/base_addr/* + CCSR*/));
+               return CAN_IRQ_NONE;
+       }
+       
+       DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx irqreg=0x%.4x\n",
+            pchip->chip_idx,
+            (long)( pchip->/*v*/base_addr/* + CCSR*/),
+            irqreg);
+
+
+       
+    #ifdef REGDUMP
+       c_can_registerdump(pchip);
+    #endif
+
+/*
+#ifdef CAN_DEBUG
+       if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) ))) {
+               DEBUGMSG("Failed to map Interrupt Controller IO-memory\n");
+       }
+       else {
+
+   DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
+               (unsigned long)0X80024000,
+             (unsigned long)0X800240CC,
+             (unsigned long)intCntrVAddr);
+       }
+
+       DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n",
+                               (long)readl(intCntrVAddr + 4));
+       DEBUGMSG("Current Interrupt ID: %d\n",
+                               (int)(readl(intCntrVAddr + 0x90) & 0xF));
+       iounmap( (void*)intCntrVAddr);
+       DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n",
+             (unsigned long)intCntrVAddr);
+#endif
+*/
+       while ( irqreg ){
+               // Handle change in status register
+           
+               if ( irqreg == INT_STAT ) {
+                       chip_status = c_can_read_reg_w( pchip, CCSR );
+                       DEBUGMSG( "(c%d)Status register: 0x%x\n",
+                               pchip->chip_idx, chip_status );
+               
+                       if ( chip_status & SR_EWARN ) {
+                               // There is an abnormal # of errors
+                           #ifdef CAN_WITH_STATISTICS
+                               pchip->stat.cntWarnings++;
+                           #endif /*CAN_WITH_STATISTICS*/
+                               errcount = c_can_read_reg_w( pchip, CCEC);
+                               DEBUGMSG("(c%d)stat: c_can_irq_handler: Abnormal number of Errors Warning\n"
+                                        "       txErr=%d, rxErr=%d\n",
+                                       pchip->chip_idx, (errcount&0x00ff), ((errcount&0x7f00)>>8));
+
+                               /*
+                               // this code deactivates the chip if the transmiterrorcounter grew above 127
+                               if ((pchip->stat.cntWarnings > 100) && ((errcount&0x00ff) > 127))
+                               {
+                                       CANMSG("(c%d)to much Errornumber warnings (>100), deactivating chip",
+                                       pchip->chip_idx);
+                                       pchip->config_irqs(pchip, 0);
+                                       pchip->enable_configuration(pchip);
+                                       pchip->clear_objects(pchip);
+                                       pchip->flags &= ~CHANNEL_CONFIGURED;
+                                       return;
+                               }*/
+                       }
+
+                       if ( chip_status & SR_EPASS ) {
+                               // There is an abnormal # of errors
+                           #ifdef CAN_WITH_STATISTICS
+                               pchip->stat.cntErrPassive++;
+                           #endif /*CAN_WITH_STATISTICS*/
+                               DEBUGMSG("(c%d)stat: c_can_irq_handler: Chip entering Error Passive Mode\n",
+                               pchip->chip_idx);
+                       }
+
+                       if ( chip_status & SR_BOFF ) {
+                               // We have a bus off condition
+                           #ifdef CAN_WITH_STATISTICS
+                               pchip->stat.cntBusOff++;
+                           #endif /*CAN_WITH_STATISTICS*/
+                               //pchip->fifo->tx_in_progress = 0;
+                               //reset init bit
+                               CANMSG("(c%d)stat: c_can_irq_handler: Bus Off\n",
+                                       pchip->chip_idx);
+                               /*if (pchip->stat.cntBusOff > 100)
+                               {
+                               CANMSG("(c%d)to much busoff warnings (>100), deactivating chip",
+                                       pchip->chip_idx);
+                               pchip->config_irqs(pchip, 0);
+                               pchip->enable_configuration(pchip);
+                               pchip->clear_objects(pchip);
+                               pchip->flags &= ~CHANNEL_CONFIGURED;
+                               return;
+                               }
+                               else*/
+                               CANMSG("(c%d)try to reconnect",
+                                       pchip->chip_idx);
+                               pchip->chipspecops->disable_configuration(pchip);
+                       }
+
+                       if (chip_status & SR_TXOK) {
+                               DEBUGMSG("(c%d)stat: Transmitted a Message successfully\n",
+                                       pchip->chip_idx);
+                               c_can_write_reg_w(pchip, chip_status & ~SR_TXOK, CCSR);
+                       }
+               
+                       if (chip_status & SR_RXOK) {
+                               DEBUGMSG("(c%d)stat: Received a Message successfully\n",
+                                       pchip->chip_idx);
+                               c_can_write_reg_w(pchip, chip_status & ~SR_RXOK, CCSR);
+                       }
+               
+                   #ifdef CAN_WITH_STATISTICS
+                       // Errors to statistics
+                       switch( chip_status & 0x07 )
+                       {
+                               case SRLEC_NE: // No error
+                                       break;
+                               case SRLEC_SE: // Stuff error
+                                       pchip->stat.cntStuffErr++;
+                                       break;
+                               case SRLEC_FE: // Form error
+                                       pchip->stat.cntFormErr++;
+                                       break;
+                               case SRLEC_AE: // Ack error
+                                       pchip->stat.cntAckErr++;
+                                       break;
+                               case SRLEC_B1: // Bit 1 error
+                                       pchip->stat.cntBit1Err++;
+                                       break;
+                               case SRLEC_B0: // Bit 0 error
+                                       pchip->stat.cntBit0Err++;
+                                       break;
+                               case SRLEC_CR: // CRC error
+                                       pchip->stat.cntCrcErr++;
+                                       break;
+                               case 7: // unused
+                                       break;
+                       }
+                   #endif /*CAN_WITH_STATISTICS*/
+                       //return; // continue?
+               } else {
+                       if (irqreg >0 && irqreg <33) {
+                               struct msgobj_t *pmsgobj;
+                               int idxobj;
+                               
+                               //get id
+                               idxobj = irqreg-1;
+                               pmsgobj=pchip->msgobj[idxobj];
+                               
+                               //DEBUGMSG( "Interrupt handler: addr=%lx devid=%lx irqreq=%x status=0x%x\n",
+                               //            (unsigned long)pchip->vbase_addr + iIRQ,
+                               //      (unsigned long)dev_id,
+                               //      irqreg,
+                               //      statreg );
+                               //
+                               spin_lock( &c_can_if1lock );
+               
+                               //Message Lost Check
+                               if (c_can_if1_busycheck(pchip)) ; /*??????????*/
+                               c_can_write_reg_w(pchip, msgLstReadMaskCM, CCIF1CM);
+                               c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
+               
+                               if (c_can_if1_busycheck(pchip)) ; /*??????????*/
+                               tempCntlReg = c_can_read_reg_w( pchip, CCIF1DMC );
+
+                               if (tempCntlReg & IFXMC_MSGLST) {
+                                       CANMSG("(c%dm%d)Chip lost a message\n",
+                                               pchip->chip_idx, pmsgobj->object);
+                                   #ifdef CAN_WITH_STATISTICS
+                                       pchip->stat.cntMsgLst++;
+                                   #endif /*CAN_WITH_STATISTICS*/
+                      
+                                       //Reset Message Lost Bit
+                                       tempCntlReg = tempCntlReg & (~IFXMC_MSGLST);
+                                       c_can_write_reg_w(pchip, tempCntlReg, CCIF1DMC);
+                                       c_can_write_reg_w(pchip, msgLstWriteMaskCM, CCIF1CM);
+                                       c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
+                               }
+
+                               //transfer Message Object to IF1 Buffer
+                               if (c_can_if1_busycheck(pchip)) ;
+                               c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
+                               c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
+
+                               if (c_can_if1_busycheck(pchip)) ;
+                               if (c_can_read_reg_w(pchip, CCIF1A2) & IFXARB2_DIR) {
+                                       spin_unlock( &c_can_if1lock );
+                                       c_can_irq_write_handler(pchip,idxobj);
+                               } else {
+                                       if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) {
+                                               id0=c_can_read_reg_w(pchip, CCIF1A1);
+                                               id1=(c_can_read_reg_w(pchip, CCIF1A2)&0x1FFF)<<16;
+                                               msgid= id0|id1;
+                                       } else {
+                                               msgid=((c_can_read_reg_w(pchip, CCIF1A2)&0x1FFC)>>2)&0x7FF;
+                                       }
+                                       spin_unlock( &c_can_if1lock );
+
+                                       spin_lock(&hardware_p->rtr_lock);
+                                       while ( rtr_search != NULL )
+                                       {
+                                               if ( rtr_search->id == msgid ) {
+                                                       break;
+                                               }
+                                               rtr_search = rtr_search->next;
+                                       }
+                                       spin_unlock(&hardware_p->rtr_lock);
+
+                                       spin_lock( &c_can_if1lock );
+
+                                       //transfer Message Object to IF1 Buffer
+                                       if (c_can_if1_busycheck(pchip)) ;
+                                       c_can_write_reg_w(pchip, readMaskCM, CCIF1CM);
+                                       c_can_write_reg_w(pchip, idxobj+1, CCIF1CR);
+                       
+                                       if (c_can_if1_busycheck(pchip)) ;
+                       
+                                       if ( ( rtr_search != NULL ) && (rtr_search->id == msgid ) ) {
+                                               c_can_irq_rtr_handler( pchip, idxobj, msgid );
+                                       } else {
+                                               c_can_irq_read_handler( pchip, idxobj, msgid );
+                                       }
+                                       spin_unlock( &c_can_if1lock );
+                       
+                                       //}
+                               }
+                       //else
+                       }
+               //if
+               }
+               // Get irq status again
+               irqreg = c_can_read_reg_w( pchip, CCINTR );
+       }
+       return CAN_IRQ_HANDLED;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// c_can_irq_rtr_handler
+//
+
+void c_can_irq_rtr_handler( struct chip_t *pchip, int idxobj, u32 msgid   )
+{
+       short int i=0;
+       struct rtr_id *prtr_search = hardware_p->rtr_queue;
+       union c_can_data rtrData;
+       
+       spin_lock( &hardware_p->rtr_lock );
+       
+       prtr_search->rtr_message->id = msgid;
+       prtr_search->rtr_message->length =
+               ( c_can_read_reg_w( pchip, CCIF1DMC ) & 0x000f);
+       
+       // Fetch message bytes
+       if (prtr_search->rtr_message->length > 0)
+               rtrData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1);
+       if (prtr_search->rtr_message->length > 2)
+               rtrData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2);
+       if (prtr_search->rtr_message->length > 4)
+               rtrData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1);
+       if (prtr_search->rtr_message->length > 6)
+               rtrData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2);
+       
+       for ( i=0; i<prtr_search->rtr_message->length; i++ ) {
+               prtr_search->rtr_message->data[ i ] = rtrData.bdata[i];
+       }
+       
+       spin_unlock( &hardware_p->rtr_lock );
+       wake_up_interruptible( &prtr_search->rtr_wq );
+       return;
+}
+
diff --git a/lincan/src/hms30c7202_can.c b/lincan/src/hms30c7202_can.c
new file mode 100644 (file)
index 0000000..2bf38aa
--- /dev/null
@@ -0,0 +1,436 @@
+/* hms30c7202_can.c - Hynix HMS30c7202 ARM device specific code
+ * Linux CAN-bus device driver.
+ * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de
+ * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
+ * and Ake Hedman, eurosource, akhe@eurosource.se
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
+ * This software is released under the GPL-License.
+ * Version lincan-0.2  9 Jul 2003
+ */
+
+#include <linux/delay.h>
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/c_can.h"
+#include "../include/hms30c7202_can.h"
+
+/*
+ * IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ */
+#define IO_RANGE 0x17E
+
+/**
+ * hms30c7202_request_io: - reserve io or memory range for can board
+ * @candev: pointer to candevice/board which asks for io. Field @io_addr
+ *     of @candev is used in most cases to define start of the range
+ *
+ * The function hms30c7202_request_io() is used to reserve the io-memory. If your
+ * hardware uses a dedicated memory range as hardware control registers you
+ * will have to add the code to reserve this memory as well. 
+ * %IO_RANGE is the io-memory range that gets reserved, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/template.c
+ */
+int hms30c7202_request_io(struct candevice_t *candev)
+{
+       DEBUGMSG("(c%d)calling hms30c7202_request_io(...)\n", pchip->chip_nr);
+
+       if(!can_request_mem_region(candev->io_addr, IO_RANGE, DEVICE_NAME )) {
+               CANMSG("hmsc30c7202_can failed to request mem region %lx.\n",
+               (unsigned long)candev->io_addr );
+       }
+       
+       if (!( candev->dev_base_addr = (long)ioremap( candev->io_addr, IO_RANGE ))) {
+               DEBUGMSG( "Failed to map IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
+                       (unsigned long)candev->io_addr,
+                       (unsigned long)candev->io_addr + IO_RANGE - 1,
+                       (unsigned long)candev->dev_base_addr);
+               can_release_mem_region(candev->io_addr, IO_RANGE);
+               return -ENODEV;
+       } else {
+       
+               DEBUGMSG( "Mapped IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
+                       (unsigned long)candev->io_addr,
+                       (unsigned long)candev->io_addr + IO_RANGE - 1,
+                       (unsigned long)candev->dev_base_addr);
+       
+       }
+       
+       candev->chip[0]->chip_base_addr=candev->dev_base_addr;
+       
+       //pchip->write_register(0, pchip->vbase_addr + CCCR);
+       //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n",
+       //      (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR)));
+       candev->chip[0]->chipspecops->start_chip(candev->chip[0]);
+       //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n",
+       //      (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR)));
+       
+       //DEBUGMSG("hms30c7202_can request i/o, leaving.\n");
+       return 0;
+}
+
+
+/**
+ * hms30c7202_release_io - free reserved io memory range
+ * @candev: pointer to candevice/board which releases io
+ *
+ * The function hms30c7202_release_io() is used to free reserved io-memory.
+ * In case you have reserved more io memory, don't forget to free it here.
+ * IO_RANGE is the io-memory range that gets released, please adjust according
+ * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
+ * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
+ * Return Value: The function always returns zero
+ * File: src/template.c
+ */
+int hms30c7202_release_io(struct candevice_t *candev)
+{
+       u16 tempReg;
+       
+       //disable IRQ generation
+       tempReg = hms30c7202_read_reg_w(candev->chip[0], CCCR);
+
+       c_can_config_irqs(candev->chip[0], 0);
+       
+       /*  // clear all message objects
+       for (i=1; i<=15; i++) {
+       ccscan_write_register(
+                       INTPD_RES |
+                       RXIE_RES |
+                       TXIE_RES |
+                       MVAL_RES,
+                       pchip->vbase_addr +
+                       i*0x10 + iMSGCTL0 );
+       ccscan_write_register(
+                       NEWD_RES |
+                       MLST_RES |
+                       CPUU_RES |
+                       TXRQ_RES |
+                       RMPD_RES,
+                       pchip->vbase_addr +
+                       i*0x10 + iMSGCTL1 );
+       }
+       */
+       // power down HMS30c7202 - C_CAN
+       candev->chip[0]->chipspecops->stop_chip(candev->chip[0]);
+       
+       // release I/O memory mapping
+       iounmap((void*)candev->dev_base_addr);
+       
+       // Release the memory region
+       can_release_mem_region(candev->io_addr, IO_RANGE);
+       
+       return 0;
+}
+
+/**
+ * hms30c7202_reset - hardware reset routine
+ * @card: Number of the hardware card.
+ *
+ * The function hms30c7202_reset() is used to give a hardware reset. This is
+ * rather hardware specific so I haven't included example code. Don't forget to
+ * check the reset status of the chip before returning.
+ * Return Value: The function returns zero on success or %-ENODEV on failure
+ * File: src/template.c
+ */
+int hms30c7202_reset(  struct candevice_t *candev)
+{
+       int i=0;
+       int enableTest=0, disableTest=0;
+       struct chip_t *pchip = candev->chip[0];
+       
+       enableTest = pchip->chipspecops->enable_configuration(pchip);
+       disableTest = pchip->chipspecops->disable_configuration(pchip);
+       if( enableTest || disableTest) {
+               CANMSG("Reset status timeout!\n");
+               CANMSG("Please check your hardware.\n");
+               return -ENODEV;
+       }
+       
+       /* Check busoff status */
+       
+       while ( (hms30c7202_read_reg_w(pchip, CCSR) & SR_BOFF) && (i<=15)) {
+               udelay(20000);
+               i++;
+       }
+       if (i>=15) {
+               CANMSG("Reset status timeout!\n");
+               CANMSG("Please check your hardware.\n");
+               return -ENODEV;
+       }
+       else
+               DEBUGMSG("Chip0 reset status ok.\n");
+       
+       //pchip->config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE);
+       return 0;
+}
+
+#define RESET_ADDR 0x0
+#define NR_C_CAN 1
+#define NR_MSGOBJ 32
+
+/**
+ * hms30c7202_init_hw_data - Initialize hardware cards
+ * @candev: Pointer to candevice/board structure
+ *
+ * The function hms30c7202_init_hw_data() is used to initialize the hardware
+ * structure containing information about the installed CAN-board.
+ * %RESET_ADDR represents the io-address of the hardware reset register.
+ * %NR_82527 represents the number of intel 82527 chips on the board.
+ * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
+ * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
+ * the hardware uses programmable interrupts.
+ * Return Value: The function always returns zero
+ * File: src/template.c
+ */
+int hms30c7202_init_hw_data(struct candevice_t *candev) 
+/*( struct chip_t *pchip, u16 chip_nr, u16 startminor, u32 baseaddr, u8 irq )*/
+{
+       //      u32 intCntrVAddr = 0;
+       u32 gpioVAddr = 0;
+       u32 tempReg = 0;
+       u32 baseaddr=candev->io_addr;
+       
+       //      if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) ))
+       //              & (! ( gpioVAddr = (u32)ioremap( 0x80023000, 0xAD ) ))) {
+       //              DEBUGMSG("Failed to map Int and GPIO memory\n");
+       //              return -EIO;
+       //      }
+       if ( ! ( gpioVAddr = (u32)ioremap( 0x80023000, 0xAD ) )) {
+               DEBUGMSG("Failed to map GPIO memory\n");
+               return -EIO;
+       } else {
+       
+               //   DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
+               //            (unsigned long)0X80024000,
+               //            (unsigned long)0X800240CC,
+               //            (unsigned long)intCntrVAddr);
+               DEBUGMSG( "Mapped GPIO IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
+                       (unsigned long)0X80023000,
+                       (unsigned long)0X800240AC,
+                       (unsigned long)gpioVAddr);
+       }
+       
+       if (baseaddr == 0x8002f000) {
+               //              tempReg = readl(intCntrVAddr);
+               //              DEBUGMSG("Read Interrupt Enable Register : 0x%.4lx\n",(long)tempReg);
+               //              DEBUGMSG("Trying to activate CAN0 Interrupt (Bit 18)\n");
+               //              writel((tempReg | (1<<18)), intCntrVAddr);
+               //              tempReg = readl(intCntrVAddr);
+               //              DEBUGMSG("Read changed Interrupt Enable Register : 0x%.4lx\n",(long)tempReg);
+               tempReg = readl(gpioVAddr + 0x5C);
+               DEBUGMSG("Read GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg);
+               DEBUGMSG("Trying to activate CAN0 (Bit 1 = 0 for CANTx0, Bit 2 = 0 for CANRx0,)\n");
+               writel(tempReg & ~0x6, gpioVAddr + 0x5C);
+               tempReg = readl(gpioVAddr + 0x5C);
+               DEBUGMSG("Read changed GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg);
+               tempReg = readl(gpioVAddr + 0x44);
+               DEBUGMSG("Read GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg);
+               DEBUGMSG("Trying to set CAN0 directions (Bit 1 = 0 for CANTx0 as OUT, Bit 2 = 1 for CANRx0 as IN,)\n");
+               writel((tempReg & ~0x2) | 0x4, gpioVAddr + 0x44);
+               tempReg = readl(gpioVAddr + 0x44);
+               DEBUGMSG("Read changed GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg);
+       }
+       else if (baseaddr == 0x80030000) {
+               //              tempReg = readl(intCntrVAddr);
+               //              writel((tempReg | (1<<19)), intCntrVAddr);
+               tempReg = readl(gpioVAddr + 0x9C);
+               DEBUGMSG("Read GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg);
+               DEBUGMSG("Trying to activate CAN1 (Bit 22 = 0 for CANRx1, Bit 23 = 0 for CANTx1,)\n");
+               writel(tempReg & 0xFF3FFFFF, gpioVAddr + 0x9C);
+               tempReg = readl(gpioVAddr + 0x9C);
+               DEBUGMSG("Read changed GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg);
+               tempReg = readl(gpioVAddr + 0x84);
+               DEBUGMSG("Read GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg);
+               DEBUGMSG("Trying to set CAN1 directions (Bit 22 = 1 for CANRx1 as IN, Bit 23 = 0 for CANTx1 as OUT,)\n");
+               writel((tempReg & ~(1<<23)) | 1<<22, gpioVAddr + 0x84);
+               tempReg = readl(gpioVAddr + 0x84);
+               DEBUGMSG("Read changed GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg);
+       }
+
+       //DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n",
+       //                      (long)readl(intCntrVAddr + 4));
+       //DEBUGMSG("Current Interrupt ID: %d\n",
+       //                      (int)(readl(intCntrVAddr + 0x90) & 0xF));
+       //      iounmap( (void*)intCntrVAddr);
+       iounmap( (void*)gpioVAddr );
+       //      DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n",
+       //            (unsigned long)intCntrVAddr);
+       DEBUGMSG( "Unmapped GPIO IO-memory: 0x%lx\n",
+               (unsigned long)gpioVAddr);
+
+       // Initialize chip data ( only one chip )
+       //  pcandev->pchip[ 0 ]->powner = pcandev;
+       /*pchip->ntype = CAN_CHIPTYPE_C_CAN;*/
+       
+       candev->nr_82527_chips=0;
+       candev->nr_sja1000_chips=0;
+       candev->nr_all_chips=NR_C_CAN;
+
+       // Register hardware operations
+       candev->hwspecops->request_io = hms30c7202_request_io;
+       candev->hwspecops->release_io = hms30c7202_release_io;
+       candev->hwspecops->reset = hms30c7202_reset;
+       /* private register read and write routines used */
+       candev->hwspecops->write_register = NULL; /*hms30c7202_write_register;*/
+       candev->hwspecops->read_register = NULL; /*hms30c7202_read_register;*/
+
+       return 0;
+}
+
+
+#define CHIP_TYPE "c_can"
+/**
+ * hms30c7202_init_chip_data - Initialize chips
+ * @candev: Pointer to candevice/board structure
+ * @chipnr: Number of the CAN chip on the hardware card
+ *
+ * The function hms30c7202_init_chip_data() is used to initialize the hardware
+ * structure containing information about the CAN chips.
+ * %CHIP_TYPE represents the type of CAN chip.
+ * The @chip_base_addr entry represents the start of the 'official' memory map
+ * of the installed chip. It's likely that this is the same as the @io_addr
+ * argument supplied at module loading time.
+ * The @clock entry holds the chip clock value in Hz.
+ * File: src/template.c
+ */
+int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr)
+{
+       candev->chip[chipnr]->chip_type=CHIP_TYPE;
+       candev->chip[chipnr]->chip_base_addr=candev->io_addr;
+       
+       candev->chip[chipnr]->clock = 16000000;
+       
+       candev->chip[chipnr]->max_objects = NR_MSGOBJ;
+       
+       /*candev->chip[chipnr]->int_clk_reg = 0x0;
+       candev->chip[chipnr]->int_bus_reg = 0x0;
+       candev->chip[chipnr]->sja_cdr_reg = 0x0;
+       candev->chip[chipnr]->sja_ocr_reg = 0x0;*/
+       
+       // Register chip operations
+       c_can_register(candev->chip[chipnr]->chipspecops);
+
+       return 0;
+}
+
+
+/**
+ * hms30c7202_init_obj_data - Initialize message buffers
+ * @chip: Pointer to chip specific structure
+ * @objnr: Number of the message buffer
+ *
+ * The function hms30c7202_init_obj_data() is used to initialize the hardware
+ * structure containing information about the different message objects on the
+ * CAN chip. 
+ * The entry @obj_base_addr represents the first memory address of the message 
+ * object. 
+ * Unless the hardware uses a segmented memory map, flags can be set zero.
+ * Return Value: The function always returns zero
+ * File: src/template.c
+ */
+int hms30c7202_init_obj_data(struct chip_t *chip, int objnr)
+{
+
+       DEBUGMSG("(c%d)calling hms30c7202_init_obj_data( ...)\n", pchip->chip_nr);
+
+       /* It seems, that there is no purpose to setup object base address */
+       chip->msgobj[objnr]->obj_base_addr=0;
+       
+       /*can_msgobj_test_fl(pmsgobj,RX_MODE_EXT);*/
+       return 0;
+}
+
+/**
+ * hms30c7202_write_register - Low level write register routine
+ * @data: data to be written
+ * @address: memory address to write to
+ *
+ * The function hms30c7202_write_register() is used to write to hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific write process.
+ * Return Value: The function does not return a value
+ * File: src/template.c
+ */
+
+void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg)
+{
+   int i;
+   u32 address = pchip->chip_base_addr + reg;
+       //unsigned long usecs = 1;
+
+   //DEBUGMSG("Trying to write 0x%u16x to address 0x%lx\n",data,address);
+
+   writew(data,address);
+       //udelay( usecs );
+   for (i=0; i<5; i++);
+}
+
+/**
+ * hms30c7202_read_register - Low level read register routine
+ * @address: memory address to read from
+ *
+ * The function hms30c7202_read_register() is used to read from hardware registers
+ * on the CAN chip. You should only have to edit this function if your hardware
+ * uses some specific read process.
+ * Return Value: The function returns the value stored in @address
+ * File: src/template.c
+ */
+u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg)
+{
+   u16 value, i;
+   u32 address = pchip->chip_base_addr + reg;
+       //unsigned long usecs = 1;
+
+   //DEBUGMSG("Trying to read from address 0x%lx :",address);
+
+   value = readw(address);
+   //udelay( usecs );
+   for (i=0;i<5;i++);
+   value = readw(address);
+       //udelay( usecs );
+   for (i=0;i<5;i++);
+
+   //DEBUGMSG("0x%u16x\n",value);
+   return value;
+
+}
+
+/**
+ * hms30c7202_program_irq - program interrupts
+ * @candev: Pointer to candevice/board structure
+ *
+ * The function hms30c7202_program_irq() is used for hardware that uses 
+ * programmable interrupts. If your hardware doesn't use programmable interrupts
+ * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
+ * leave this function unedited. Again this function is hardware specific so 
+ * there's no example code.
+ * Return value: The function returns zero on success or %-ENODEV on failure
+ * File: src/template.c
+ */
+int hms30c7202_program_irq(struct candevice_t *candev)
+{
+       return 0;
+}
+
+int hms30c7202_register(struct hwspecops_t *hwspecops)
+{
+       hwspecops->request_io = hms30c7202_request_io;
+       hwspecops->release_io = hms30c7202_release_io;
+       hwspecops->reset = hms30c7202_reset;
+       hwspecops->init_hw_data = hms30c7202_init_hw_data;
+       hwspecops->init_chip_data = hms30c7202_init_chip_data;
+       hwspecops->init_obj_data = hms30c7202_init_obj_data;
+       /* private register read and write routines used */
+       hwspecops->write_register = NULL; /*hms30c7202_write_register;*/
+       hwspecops->read_register = NULL; /*hms30c7202_read_register;*/
+       hwspecops->program_irq = hms30c7202_program_irq;
+       return 0;
+}
+
index 6897948..03c2dce 100644 (file)
@@ -280,18 +280,29 @@ int i82527_config_irqs(struct chip_t *chip, short irqs)
 
 int i82527_pre_read_config(struct chip_t *chip, struct msgobj_t *obj)
 {
-       if (extended) {
+       unsigned long id=obj->rx_preconfig_id;
+
+       can_msgobj_set_fl(obj,RX_MODE);
+
+       if (extended || can_msgobj_test_fl(obj,RX_MODE_EXT)) {
+               id<<=3;
+               canobj_write_reg(chip,obj,id,iMSGID3);
+               canobj_write_reg(chip,obj,id>>8,iMSGID2);
+               canobj_write_reg(chip,obj,id>>16,iMSGID1);
+               canobj_write_reg(chip,obj,id>>24,iMSGID0);
                canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG);
-       }
-       else {
+       } else {
+               id<<=5;
+               canobj_write_reg(chip,obj,id,iMSGID1);
+               canobj_write_reg(chip,obj,id>>8,iMSGID0);
                canobj_write_reg(chip,obj,0x00,iMSGCFG);
        }
+
        canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1);
        canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0);
 
        DEBUGMSG("i82527_pre_read_config: configured obj at 0x%08lx\n",obj->obj_base_addr);
 
-       
        return 0;
 }
 
@@ -304,6 +315,8 @@ int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
        len = msg->length;
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
 
+       can_msgobj_clear_fl(obj,RX_MODE);
+
        canobj_write_reg(chip,obj,(MVAL_SET|TXIE_SET|RXIE_RES|INTPD_RES),iMSGCTL0);
        canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_SET|NEWD_RES),iMSGCTL1);
 
@@ -549,33 +562,21 @@ static inline
 void i82527_irq_update_filter(struct chip_t *chip, struct msgobj_t *obj)
 {
        struct canfilt_t filt;
-       unsigned long id;
 
        if(canqueue_ends_filt_conjuction(obj->qends, &filt)) {
+               obj->rx_preconfig_id=filt.id;
                canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),iMSGCTL0);
                if(obj->object == 15) {
                        i82527_message15_mask(chip,filt.id,filt.mask);
                }
-               if (filt.flags&MSG_EXT) {
-                       id=filt.id<<3;
-                       canobj_write_reg(chip,obj,id,iMSGID3);
-                       canobj_write_reg(chip,obj,id>>8,iMSGID2);
-                       canobj_write_reg(chip,obj,id>>16,iMSGID1);
-                       canobj_write_reg(chip,obj,id>>24,iMSGID0);
-                       canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG);
-               }
-               else {
-                       id=filt.id<<5;
-                       canobj_write_reg(chip,obj,id,iMSGID1);
-                       canobj_write_reg(chip,obj,id>>8,iMSGID0);
-                       canobj_write_reg(chip,obj,0x00,iMSGCFG);
-               }
+               if (filt.flags&MSG_EXT)
+                       can_msgobj_set_fl(obj,RX_MODE_EXT);
+               else
+                       can_msgobj_clear_fl(obj,RX_MODE_EXT);
 
-               canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1);
-               canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0);
+               i82527_pre_read_config(chip, obj);
 
                CANMSG("i82527_irq_update_filter: obj at 0x%08lx\n",obj->obj_base_addr);
-               
        }
 }
 
@@ -717,8 +718,6 @@ int i82527_filtch_rq(struct chip_t *chip, struct msgobj_t *obj)
 
        can_preempt_enable();
        return 0;
-
-       return 0;
 }
 
 int i82527_register(struct chipspecops_t *chipspecops)
index cfe5856..2d17861 100644 (file)
@@ -54,7 +54,7 @@ int pcm3680_request_io(struct candevice_t *candev)
 }
 
 /**
- * template_elease_io - free reserved io memory range
+ * template_release_io - free reserved io memory range
  * @candev: pointer to candevice/board which releases io
  *
  * The function template_release_io() is used to free reserved io-memory.
index 488d8e1..66466d6 100644 (file)
@@ -918,7 +918,7 @@ int unican_pci_init_chip_data(struct candevice_t *candev, int chipnr)
 {
        int ret;
        candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq;
-       ret = unican_pci_init_chip_data(candev, chipnr);
+       ret = unican_init_chip_data(candev, chipnr);
        candev->chip[chipnr]->flags |= CHIP_IRQ_PCI;
        return ret;
 }