]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/hcan2.c
Merge branch 'master' into can-usb1
[lincan.git] / lincan / src / hcan2.c
index 96b104361330119ebd1a697f0ff43b5af089c7e0..279a4e98d16184e03de1d7d7dda3e1bed312664c 100644 (file)
@@ -1,7 +1,37 @@
-/* hcan2.c
- * Linux CAN-bus device driver.
- * This software is released under the GPL-License.
- */
+/**************************************************************************/
+/* File: hcan2.c - Renesas SH7760 HCAN2 controller support                */
+/*                                                                        */
+/* LinCAN - (Not only) Linux CAN bus driver                               */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
+/* Copyright (C) 2007-2008 Martin Petera <peterm4@fel.cvut.cz>            */
+/* Funded by OCERA and FRESCOR IST projects                               */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
+/*                                                                        */
+/* LinCAN is free software; you can redistribute it and/or modify it      */
+/* under terms of the GNU General Public License as published by the      */
+/* Free Software Foundation; either version 2, or (at your option) any    */
+/* later version.  LinCAN 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 LinCAN; see file     */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
+/* Cambridge, MA 02139, USA.                                              */
+/*                                                                        */
+/* To allow use of LinCAN in the compact embedded systems firmware        */
+/* and RT-executives (RTEMS for example), main authors agree with next    */
+/* special exception:                                                     */
+/*                                                                        */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce    */
+/* an application image/executable, does not by itself cause the          */
+/* resulting application image/executable to be covered by                */
+/* the GNU General Public License.                                        */
+/* This exception does not however invalidate any other reasons           */
+/* why the executable file might be covered by the GNU Public License.    */
+/* Publication of enhanced or derived LinCAN files is required although.  */
+/**************************************************************************/
 
 #include "../include/can.h"
 #include "../include/can_sysdep.h"
@@ -32,18 +62,21 @@ void hcan2_setup_mbox4read(struct msgobj_t * obj);
 void hcan2_setup_ctrl_regs(struct canmsg_t * msg, uint16_t * ctrl0, uint16_t * ctrl1, uint16_t * ctrl2);
 
 int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg);
-
+void hcan2_notifyRXends(struct msgobj_t * obj, int what);
 /* Enable folowing IRQs
  * HCAN2_IRR_DFRI = Data Frame Received Interrupt Flag
  * HCAN2_IRR_MBEI = Mailbox Empty Interrupt Flag
+ *
+ * and Errors:
+ * Bus Off, Error Passive, Message Overrun/Overwrite
  */
-uint16_t IRQs = ~(HCAN2_IRR_DFRI + HCAN2_IRR_MBEI);
+uint16_t IRQs = ~(HCAN2_IRR_DFRI + HCAN2_IRR_MBEI + HCAN2_IRR_BOI + HCAN2_IRR_EPI + HCAN2_IRR_MOOI);
 /* 1 - mask interrupt, 0 - interrupt not masked */
 
 int hcan2_chip_config(struct canchip_t *chip)
 {
        DEBUGMSG("Configuring chip...\n");
-       
+
        if (hcan2_enable_configuration(chip))
                return -ENODEV;
 
@@ -203,7 +236,7 @@ int hcan2_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, int sa
        bcr1 = (((tseg1 - 1) & 0x000f) << 12) + (((tseg2 - 1) & 0x0007) << 8) + ((sjw & 0x0003) << 4);
        bcr0 = (best_brp - 1) & 0x00ff;
 
-       hcan2_set_btregs(chip, bcr0, bcr1);     
+       hcan2_set_btregs(chip, bcr0, bcr1);
 
        hcan2_disable_configuration(chip);
 
@@ -221,7 +254,7 @@ int hcan2_set_btregs(struct canchip_t *chip, unsigned short bcr0, unsigned short
 
        can_write_reg_w(chip, bcr1, HCAN2_BCR1);
        can_write_reg_w(chip, bcr0, HCAN2_BCR0);
-       
+
 /*     DEBUGMSG("BCR0 and BCR1 successfully set.\n"); */
        return 0;
 }
@@ -256,8 +289,8 @@ int hcan2_stop_chip(struct canchip_t *chip)
 int hcan2_attach_to_chip(struct canchip_t *chip)
 {
 /*     DEBUGMSG("Attaching to chip %d.\n", chip->chip_idx); */
-       
-       /* initialize chip */   
+
+       /* initialize chip */
 
        if (hcan2_enable_configuration(chip))
                return -ENODEV;
@@ -285,9 +318,9 @@ int hcan2_release_chip(struct canchip_t *chip)
 {
        hcan2_stop_chip(chip);
        can_disable_irq(chip->chip_irq);
-       
+
        hcan2_clear_objects(chip);
-       
+
        DEBUGMSG("Chip released [%02d]\n", chip->chip_idx);
        return 0;
 }
@@ -299,27 +332,28 @@ int hcan2_standard_mask(struct canchip_t *chip, unsigned short code, unsigned sh
        struct msgobj_t * obj;
        int obj_idx = (int) (chip->chip_data);
 
-       if (code & 0x1ffff800)  
+       if (code & 0x1ffff800)
            return hcan2_extended_mask(chip, code, mask);
 
-       
+
        if (obj_idx > 0 && obj_idx <= 32)
            obj = chip->msgobj[obj_idx - 1];
        else
            return -ENODEV;
 
-       chip->chip_data = (void*)0; /* reset mbox number */
+       chip->chip_data = (void*)0;     /* reset mbox number */
 
 
        ctrl0 = ((code & 0x07ff) << 4);
        lafm0 = ((mask & 0x07ff) << 4);
-       
+       lafm0 |= 0x0003;                /* ignore Ext ID 17:16  */
+
        can_write_reg_w(chip, ctrl0, (int) obj->obj_base_addr + HCAN2_MB_CTRL0);
        can_write_reg_w(chip, 0x0000, (int) obj->obj_base_addr + HCAN2_MB_CTRL1);
        can_write_reg_w(chip, lafm0, (int) obj->obj_base_addr + HCAN2_MB_MASK);
        can_write_reg_w(chip, 0xffff, (int) obj->obj_base_addr + HCAN2_MB_MASK + 2);
 
-       DEBUGMSG("Set standard_mask [id:0x%04x, m:0x%04x]\n", code, mask);
+       DEBUGMSG("MB%02d: Set standard_mask [id:0x%04x, m:0x%04x]\n", obj_idx, code, lafm0);
        return 0;
 }
 
@@ -330,7 +364,7 @@ int hcan2_extended_mask(struct canchip_t *chip, unsigned long code, unsigned lon
        struct msgobj_t * obj;
 
        int obj_idx = (int) (chip->chip_data);
-       
+
        if (obj_idx > 0 && obj_idx <= 32)
            obj = chip->msgobj[obj_idx - 1];
        else
@@ -346,14 +380,14 @@ int hcan2_extended_mask(struct canchip_t *chip, unsigned long code, unsigned lon
        lafm0 = ((mask & 0x1ffc0000) >> 14);
        lafm0 |=((mask & 0x00030000) >> 16);
        lafm1 =  (mask & 0x0000ffff);
-       
+
        can_write_reg_w(chip, ctrl0, (int) obj->obj_base_addr + HCAN2_MB_CTRL0);
        can_write_reg_w(chip, ctrl1, (int) obj->obj_base_addr + HCAN2_MB_CTRL1);
        can_write_reg_w(chip, lafm0, (int) obj->obj_base_addr + HCAN2_MB_MASK);
        can_write_reg_w(chip, lafm1, (int) obj->obj_base_addr + HCAN2_MB_MASK + 2);
-       
-       DEBUGMSG("Set extended_mask [id:0x%08x, m:0x%08x]\n", (uint32_t)code, (uint32_t)mask);
-    
+
+       DEBUGMSG("MB%02d: Set extended_mask [id:0x%08x, m:0x%08x]\n", obj_idx, (uint32_t)code, (uint32_t)mask);
+
         return 0;
 }
 
@@ -366,7 +400,7 @@ int hcan2_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
 
        /* clears mailbox and setup LFA to accept all Exted Messages */
        hcan2_setup_mbox4read(obj);
-       
+
        hcan2_disable_configuration(chip);
 
        return 0;
@@ -376,15 +410,15 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct
 {
        DEBUGMSG("Pre write config\n");
 
-       /* change Mailbox header only if neccessary */  
+       /* change Mailbox header only if neccessary */
        /* otherwise change only data */
        if (hcan2_compare_msg(obj, msg))
        {
                if (hcan2_enable_configuration(chip))
                        return -ENODEV;
-       
+
                hcan2_setup_mbox4write(obj, msg);
-               
+
                if (hcan2_disable_configuration(chip))
                        return -ENODEV;
        }
@@ -397,25 +431,14 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct
 int hcan2_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg)
 {
        unsigned obj_bit;
-       int i;
-       int b_addr = ((obj->object - 1) / 16) * (-2); 
+       int b_addr = ((obj->object - 1) / 16) * (-2);
 
        obj_bit = (1 << ((obj->object - 1) % 16));
-       
+
 /*     CANMSG("Sending message [obj: %d]\n", obj->object - 1); */
 
        can_write_reg_w(chip, obj_bit, b_addr + HCAN2_TXPR0);
-                       
-       /* Waits until chip sends message */
-       i = 0;
-       while (hcan2_check_tx_stat(chip) && ((i++) <= MAX_TRANSMIT_WAIT_LOOPS))
-           udelay(200);
 
-       if (i >= MAX_TRANSMIT_WAIT_LOOPS) {
-               CANMSG("Failed while waiting for Transmitt finished\n");
-               return -ENODEV;
-       }
-       
 /*     CANMSG("Message sent [obj: %d]\n", obj->object - 1); */
        return 0;
 }
@@ -432,11 +455,25 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
        uint16_t irq_reg, idx;
        short loop_cnt = MAX_IRQ_WAIT_LOOPS;
        uint32_t rxdf, txdf;
-       struct msgobj_t * obj;
+
+/*
+       HCAN2_IRR_TCMI  - Time Compare Match Register
+       HCAN2_IRR_TOI   - Time Overrun Interrupt
+       HCAN2_IRR_WUBA  - Wake-up on Bus Activity
+       HCAN2_IRR_MOOI  - Message Overrun/Overwrite Interrupt Flag
+       HCAN2_IRR_MBEI  - Messagebox Empty Interrupt Flag
+       HCAN2_IRR_OF    - Overload Frame
+       HCAN2_IRR_BOI   - Bus Off Interrupt Flag
+       HCAN2_IRR_EPI   - Error Passive Interrupt Flag
+       HCAN2_IRR_ROWI  - Receive Overload Warning Interrupt Flag
+       HCAN2_IRR_TOWI  - Transmit Overload Warining Interrupt Flag
+       HCAN2_IRR_RFRI  - Remote Frame Request Interrupt Flag
+       HCAN2_IRR_DFRI  - Data Frame Received Interrupt Flag
+       HCAN2_IRR_RHSI  - Reset/Halt/Sleep Interrupt Flag */
 
        irq_reg = can_read_reg_w(chip, HCAN2_IRR);
        DEBUGMSG("irq: %d, chip base addr: 0x%08x\n", irq, (uint32_t)chip->chip_base_addr);
-/*     DEBUGMSG("IRQ Handler: HCAN2_IRR: 0x%04x\n", irq_reg); */
+       DEBUGMSG("IRQ Handler: HCAN2_IRR: 0x%04x\n", irq_reg); //*/
 
        do {
 
@@ -445,37 +482,85 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                        return CANCHIP_IRQ_STUCK;
                }
 
+               /* Received message */
                if (irq_reg & HCAN2_IRR_DFRI)
-               {       /* Received message */
-                       rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
-                           can_read_reg_w(chip, HCAN2_RXPR0);
+               {
+                       rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
+                               can_read_reg_w(chip, HCAN2_RXPR0);
 
-                       DEBUGMSG("Received message [0x%08x]\n", rxdf);
+                       while(rxdf) {
+                               DEBUGMSG("Received message [0x%08x]\n", rxdf);
 
-                       while (rxdf) {
-                           /* find the message object */
-                           for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
+                               /* find the message object */
+                               for (idx = 0; (idx < chip->max_objects) && rxdf; idx++)
+                                       if ((rxdf & (1<<idx))) {
+                                               hcan2_irq_read_handler(chip, chip->msgobj[idx]);
+                                               /* RXPR flag for this msgobj is cleared during irq_read_handler*/
+                                               rxdf &= ~(1 << idx);
+                                       }
 
-                           /* realy i got one? */
-                           if (idx < chip->max_objects)
-                               hcan2_irq_read_handler(chip, chip->msgobj[idx]);
-                           else
-                               break;
 
-                           /* clear RXPR flag for this msgobj */
-                           can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_RXPR0 - 2*(idx / 16));
+                               DEBUGMSG("Before reset flags [0x%08x]\n", rxdf);
+                               rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
+                                       can_read_reg_w(chip, HCAN2_RXPR0);
+                       }
+               }
 
-                           rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) +
-                               can_read_reg_w(chip, HCAN2_RXPR0);
+               /* Error: Bus Off */
+               if (irq_reg & HCAN2_IRR_BOI) {
+                       CANMSG("Error: entering BUS OFF state\nstatus register: 0x%02x irq register: 0x%02x\n",
+                               can_read_reg_w(chip, HCAN2_GSR), irq_reg);
+
+                       /* notify all RX/TX ends */
+                       for (idx = 0; idx < chip->max_objects; idx++) {
+                               /* notify TX */
+                               chip->msgobj[idx]->ret=-1;
+                               if(chip->msgobj[idx]->tx_slot)
+                                       canque_notify_inends(chip->msgobj[idx]->tx_qedge,
+                                               CANQUEUE_NOTIFY_ERROR);
+                               /* notify RX */
+                               hcan2_notifyRXends(chip->msgobj[idx], CANQUEUE_NOTIFY_ERROR);
                        }
-                           
-                   /* reset HCAN2_IRR_DFRI flag */
-                   can_write_reg_w(chip, irq_reg & ~HCAN2_IRR_DFRI, HCAN2_IRR);
+
+                       /* reset flag - by writing '1' */
+                       can_write_reg_w(chip, HCAN2_IRR_BOI, HCAN2_IRR);
+               }
+
+               /* Warning: Error Passive */
+               if (irq_reg & HCAN2_IRR_EPI) {
+                       uint16_t tecrec;
+                       tecrec = can_read_reg_w(chip, HCAN2_TECREC);
+
+                       CANMSG("Warning: entering ERROR PASSIVE state\nTEC: %d REC: %d\n",
+                               (uint16_t)((tecrec >> 8) & 0x00ff), (uint16_t)(tecrec & 0x00ff));
+
+                       /* Show warning only */
+
+                       /* reset flag - by writing '1' */
+                       can_write_reg_w(chip, HCAN2_IRR_EPI, HCAN2_IRR);
+               }
+
+               /* Message Overrun/Overwritten */
+               if (irq_reg & HCAN2_IRR_MOOI) {
+                       /* put get Unread Message Status Register */
+                       rxdf =  (can_read_reg_w(chip, HCAN2_UMSR1) << 16) + can_read_reg_w(chip, HCAN2_UMSR0);
+
+                       /* find the message object */
+                       for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<<idx)); idx++) { }
+
+                       CANMSG("Error: MESSAGE OVERRUN/OVERWRITTEN [MB: %d]\n",idx);
+
+                       /* notify only injured RXqueue-end */
+                       if (idx < chip->max_objects)
+                               hcan2_notifyRXends(chip->msgobj[idx], CANQUEUE_NOTIFY_ERROR);
+
+                       /* reset flag */
+                       can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_UMSR0 - 2 * (idx / 16));
                }
 
-               if (irq_reg & (HCAN2_IRR_MBEI))
+               /* Mailbox empty - after message was sent */
+               if (irq_reg & HCAN2_IRR_MBEI)
                {
-                   /* Mailbox empty - after message was sent */
                    txdf = (can_read_reg_w(chip, HCAN2_TXACK1) << 16) +
                        can_read_reg_w(chip, HCAN2_TXACK0);
 
@@ -488,22 +573,17 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip)
                        can_write_reg_w(chip, 0xffff, HCAN2_ABACK0);
                        can_write_reg_w(chip, 0xffff, HCAN2_ABACK1);
                        return CANCHIP_IRQ_HANDLED;
-                   } 
-                   
-                   obj = chip->msgobj[idx];
+                   }
 
-                   /* Clear TXACK flag */                  
+                   /* Clear TXACK flag */
                    can_write_reg_w(chip, 1 << (idx % 16), HCAN2_TXACK0 - 2 * (idx / 16));
 
-                   /* sends message */     
-                   hcan2_wakeup_tx(chip, obj);
+                   /* sends message */
+                   hcan2_wakeup_tx(chip, chip->msgobj[idx]);
                }
 
-               irq_reg=can_read_reg_w(chip, HCAN2_IRR);
-       } while(irq_reg & (HCAN2_IRR_MBEI | HCAN2_IRR_DFRI));
-
-       /* reset ALL tinterrupt flags */
-       can_write_reg_w(chip, irq_reg, HCAN2_IRR);
+               irq_reg = can_read_reg_w(chip, HCAN2_IRR);
+       } while(irq_reg & ~IRQs);
 
        return CANCHIP_IRQ_HANDLED;
 }
@@ -519,11 +599,11 @@ int hcan2_config_irqs(struct canchip_t *chip, short irqs)
        hcan2_clear_irq_flags(chip);
 
        can_write_reg_w(chip, irqs, HCAN2_IMR);
-       
+
        /* allow all mailboxes to generate IRQ */
        can_write_reg_w(chip, 0, HCAN2_MBIMR0);
        can_write_reg_w(chip, 0, HCAN2_MBIMR1);
-       
+
 /*     CANMSG("IRQ Mask set [0x%02x]\n", irqs); */
        return 0;
 }
@@ -549,24 +629,41 @@ int hcan2_check_tx_stat(struct canchip_t *chip)
                return 1;
 }
 
+/* Note: this checks TX status of concrete messagebox */
+int hcan2_check_MB_tx_stat(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       /* Transmition is complete return 0 - no error */
+
+       /* MB1-MB15 are in CANTXPR0 and MB16-MB31 are in CANTXPR1
+          CANTXPR0 = CANTXPR1 + 0x0002
+          MB0 - receive only */
+
+       char id = obj->object - 1;
+       return (can_read_reg_w(chip, HCAN2_TXPR0 - 2 * (id / 16)) & (1 << (id & 0x00ff)));
+}
+
 int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
 {
        DEBUGMSG("WakeUP TX\n");
 
        if (obj->object == 1)   /* msgbox 0 cant transmit only receive ! */
            return -ENODEV;
-    
+
        can_preempt_disable();
-       
+
        can_msgobj_set_fl(obj,TX_REQUEST);
-       while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+       if(!can_msgobj_test_and_set_fl(obj,TX_LOCK) &&
+               !hcan2_check_MB_tx_stat(chip, obj))
+       {       /* enable transmition only if MB is empty */
                can_msgobj_clear_fl(obj,TX_REQUEST);
 
                hcan2_irq_write_handler(chip, obj);
-       
+
                can_msgobj_clear_fl(obj,TX_LOCK);
-               if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
        }
+       else
+               can_msgobj_clear_fl(obj,TX_REQUEST);
+
 
        can_preempt_enable();
 
@@ -590,7 +687,9 @@ int hcan2_filtch_rq(struct canchip_t *chip, struct msgobj_t * obj)
 
        /* HCAN2 uses oposite logic for LAFM: 1-ignore bit, 0-use bit as mask */
 
+#if myDEBUG
        DEBUGMSG("CNT: %d ID: 0x%08x MASK: 0x%08x\n", num, (uint32_t) (filter.id) & 0x1fffffff, (uint32_t) (~filter.mask) & 0x1fffffff);
+#endif
 
        if (filter.flags & MSG_EXT)             /* Extended ID */
                return hcan2_extended_mask(chip, filter.id, ~filter.mask);
@@ -605,7 +704,7 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
        unsigned ctrl0, ctrl2, data;
        unsigned long flag_addr;
        uint16_t mb_offset;
-       
+
 
        mb_offset = (int ) obj->obj_base_addr;
 
@@ -617,7 +716,7 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
        obj->rx_msg.length = len = ctrl2 & HCAN2_MBCT2_DLC;
        obj->rx_msg.flags = (ctrl0 & HCAN2_MBCT0_RTR) ? MSG_RTR : 0;
        obj->rx_msg.cob = obj->object - 1;
-               
+
        /* get ID of received message */
        if (ctrl0 & HCAN2_MBCT0_IDE)
        {
@@ -628,23 +727,23 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
        }
        else
            obj->rx_msg.id = (ctrl0 & HCAN2_MBCT0_STDID)>>4;
-           
+
 
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
        for (i = 0; i < len; i++)
        {
                /* rcanqueue_ends_filt_conjuctionead 16bit data - two data bytes*/
                data = can_read_reg_w(chip, (int) obj->obj_base_addr + HCAN2_MB_DATA1 + i);
-               obj->rx_msg.data[i] = (data & 0xff00) >> 8;
-               if (++i < len) obj->rx_msg.data[i] = data & 0x00ff;
+               obj->rx_msg.data[i] = (data & 0xff00) >> 8;             // one data byte
+               if (++i < len) obj->rx_msg.data[i] = data & 0x00ff;     // second data byte
        }
 
        /* Computes correct offset address of register from MSGBOX_IDX and RTR flag
         * result is one of these:
         * HCAN2_RXPR1, HCAN2_RXPR0, HCAN2_RFPR1, HCAN2_RFPR0
         */
-       flag_addr = ((ctrl0 & HCAN2_MBCT0_RTR) << 3) + HCAN2_RXPR0 - ((obj->object - 1) / 16) * 2;
-               
+       flag_addr = HCAN2_RXPR0 - (int)((obj->object - 1) / 16) * 2;
+
        /* Reset flag by writing 1 to its position */
        can_write_reg_w(chip, (1 << ((obj->object - 1) % 16)), flag_addr);
 
@@ -733,7 +832,7 @@ int hcan2_fill_chipspecops(struct canchip_t *chip)
        chip->max_objects = 32;
        chip->write_register = chip->hostdevice->hwspecops->write_register;
        chip->read_register = chip->hostdevice->hwspecops->read_register;
-       
+
        /*
        chip->flags;
        chip->baudrate;
@@ -765,7 +864,7 @@ int hcan2_reset_chip(struct canchip_t *chip)
         * 11 recessive bits to join CAN bus activity
         */
 
-       int i; 
+       int i;
        unsigned gsr_reset;
 
        DEBUGMSG("Resetting HCAN2 chip %d...\n", chip->chip_idx);
@@ -773,7 +872,7 @@ int hcan2_reset_chip(struct canchip_t *chip)
        /* send Reset Request */
        can_write_reg_w(chip, HCAN2_MCR_RESET, HCAN2_MCR );
 
-       /* Check hardware reset status */ 
+       /* Check hardware reset status */
        i = 0;
        gsr_reset = can_read_reg_w(chip, HCAN2_GSR) & HCAN2_GSR_RESET;
        while (!(gsr_reset) && ((i++) <= MAX_SETTING_WAIT_LOOPS))
@@ -880,14 +979,14 @@ void hcan2_clear_mbox(struct canchip_t *chip, int msgobj_idx)
 void hcan2_setup_mbox4write(struct msgobj_t * obj, struct canmsg_t * msg)
 {
        int mb_offset;
-       uint16_t ctrl0, ctrl1, ctrl2; 
+       uint16_t ctrl0, ctrl1, ctrl2;
 
        struct canchip_t * chip = obj->hostchip;
 
        DEBUGMSG("Change Header\n");
 
        mb_offset = (int) obj->obj_base_addr;
-       
+
        hcan2_setup_ctrl_regs(msg, &ctrl0, &ctrl1, &ctrl2);
 
        can_write_reg_w(chip, ctrl0, mb_offset + HCAN2_MB_CTRL0);
@@ -901,17 +1000,17 @@ void hcan2_setup_mbox4write(struct msgobj_t * obj, struct canmsg_t * msg)
 void hcan2_setup_mbox4write_data(struct msgobj_t * obj, struct canmsg_t * msg)
 {
        int len,i, mb_offset;
-       uint16_t data; 
-       
+       uint16_t data;
+
        struct canchip_t * chip = obj->hostchip;
 
        DEBUGMSG("Change Data\n");
 
        mb_offset = (int) obj->obj_base_addr;
-       
+
        len = msg->length;
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
-       
+
        for (i = 0; i < len; i+=2)
        {
                data = (msg->data[i] << 8) + (i+1 < len ? msg->data[i+1] : 0);
@@ -922,7 +1021,7 @@ void hcan2_setup_mbox4write_data(struct msgobj_t * obj, struct canmsg_t * msg)
 void hcan2_setup_mbox4read(struct msgobj_t * obj)
 {
        struct canchip_t * chip = obj->hostchip;
-    
+
        hcan2_clear_mbox(chip, obj->object - 1);
 
        // in structure chip->chip_data is Mailbox number
@@ -967,7 +1066,7 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg)
        uint16_t ctrl0, ctrl1, ctrl2;
        uint16_t mb_offset;
        uint16_t c0,c1,c2;
-       
+
        struct canchip_t * chip = obj->hostchip;
 
        mb_offset = (int) obj->obj_base_addr;
@@ -981,7 +1080,7 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg)
        /* if using EXT ID conpare also ctrl1 */
        if (msg->flags & MSG_EXT && ctrl1 ^ c1)
                return 1;
-               
+
 
        DEBUGMSG("C0 0x%04x HW: 0x%04x\n", ctrl0, c0);
        DEBUGMSG("C1 0x%04x HW: 0x%04x\n", ctrl1, c1);
@@ -989,3 +1088,10 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg)
 
        return ((ctrl0 ^ c0) || (ctrl2 ^ c2));
 }
+
+void hcan2_notifyRXends(struct msgobj_t * obj, int what){
+       struct canque_edge_t * edge;
+       canque_for_each_inedge(obj->qends, edge){
+               canque_notify_outends(edge, what);
+       }
+}