]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/sja1000p.c
SJA1000 driver interrupts processing modified to not rely on interrupt register for...
[lincan.git] / lincan / src / sja1000p.c
index 5deedc617d048edea6fa4edf754464ff908397c3..59fa68dcb39ed4a807ca054fd9a04445c2f165a8 100644 (file)
@@ -96,6 +96,10 @@ int sja1000p_chip_config(struct canchip_t *chip)
 
        /* Set mode, clock out, comparator */
        can_write_reg(chip,sjaCDR_PELICAN|chip->sja_cdr_reg,SJACDR); 
+
+       /* Ensure, that interrupts are disabled even on the chip level now */
+       can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
+
        /* Set driver output configuration */
        can_write_reg(chip,chip->sja_ocr_reg,SJAOCR); 
        
@@ -486,6 +490,32 @@ int sja1000p_stop_chip(struct canchip_t *chip)
        return 0;
 }
 
+/**
+ * sja1000p_attach_to_chip: - attaches to the chip, setups registers and state
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_attach_to_chip(struct canchip_t *chip)
+{
+       return 0;
+}
+
+/**
+ * sja1000p_release_chip: - called before chip structure removal if %CHIP_ATTACHED is set
+ * @chip: pointer to chip state structure
+ *
+ * Return Value: negative value reports error.
+ * File: src/sja1000p.c
+ */
+int sja1000p_release_chip(struct canchip_t *chip)
+{
+       sja1000p_stop_chip(chip);
+       can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
+
+       return 0;
+}
 
 /**
  * sja1000p_remote_request: - configures message object and asks for RTR message
@@ -573,9 +603,11 @@ void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
                obj->tx_slot=NULL;
        }
        
+       can_msgobj_clear_fl(obj,TX_PENDING);
        cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
        if(cmd<0)
                return;
+       can_msgobj_set_fl(obj,TX_PENDING);
 
        if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) {
                obj->ret = -1;
@@ -599,10 +631,7 @@ void sja1000p_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
 /**
  * sja1000p_irq_handler: - interrupt service routine
  * @irq: interrupt vector number, this value is system specific
- * @dev_id: driver private pointer registered at time of request_irq() call.
- *     The CAN driver uses this pointer to store relationship of interrupt
- *     to chip state structure - @struct canchip_t
- * @regs: system dependent value pointing to registers stored in exception frame
+ * @chip: pointer to chip state structure
  * 
  * Interrupt handler is activated when state of CAN controller chip changes,
  * there is message to be read or there is more space for new messages or
@@ -630,6 +659,8 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                return CANCHIP_IRQ_NONE;
        }
 
+       status=can_read_reg(chip,SJASR);
+
        do {
 
                if(!loop_cnt--) {
@@ -637,13 +668,18 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                        return CANCHIP_IRQ_STUCK;
                }
 
-               if ((irq_register & sjaIR_RI) != 0) {
-                       DEBUGMSG("sja1000_irq_handler: RI\n");
+               /* (irq_register & sjaIR_RI) */
+               /*      old variant using SJAIR, collides with intended use with irq_accept */
+               if (status & sjaSR_RBS) {
+                       DEBUGMSG("sja1000_irq_handler: RI or RBS\n");
                        sja1000p_read(chip,obj);
                        obj->ret = 0;
                }
-               if ((irq_register & sjaIR_TI) != 0) {
-                       DEBUGMSG("sja1000_irq_handler: TI\n");
+
+               /* (irq_register & sjaIR_TI) */
+               /*      old variant using SJAIR, collides with intended use with irq_accept */
+               if ((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) {
+                       DEBUGMSG("sja1000_irq_handler: TI or TX_PENDING and TBS\n");
                        obj->ret = 0;
                        can_msgobj_set_fl(obj,TX_REQUEST);
                        while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
@@ -659,7 +695,6 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
                }
                if ((irq_register & (sjaIR_EI|sjaIR_BEI|sjaIR_EPI|sjaIR_DOI)) != 0) { 
                        // Some error happened
-                       status=can_read_reg(chip,SJASR);
                        error_code=can_read_reg(chip,SJAECC);
                        CANMSG("Error: status register: 0x%x irq_register: 0x%02x error: 0x%02x\n",
                                status, irq_register, error_code);
@@ -692,7 +727,11 @@ int sja1000p_irq_handler(int irq, struct canchip_t *chip)
 
                irq_register=can_read_reg(chip,SJAIR);
        
-       } while(irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI));
+               status=can_read_reg(chip,SJASR);
+
+       } while((irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) ||
+               ((status & sjaSR_TBS) && can_msgobj_test_fl(obj,TX_PENDING)) ||
+               (status & sjaSR_RBS));
 
        return CANCHIP_IRQ_HANDLED;
 }
@@ -713,6 +752,7 @@ int sja1000p_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
        
        can_preempt_disable();
        
+       can_msgobj_set_fl(obj,TX_PENDING);
        can_msgobj_set_fl(obj,TX_REQUEST);
        while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
                can_msgobj_clear_fl(obj,TX_REQUEST);
@@ -749,10 +789,13 @@ int sja1000p_register(struct chipspecops_t *chipspecops)
        chipspecops->remote_request=sja1000p_remote_request;
        chipspecops->enable_configuration=sja1000p_enable_configuration;
        chipspecops->disable_configuration=sja1000p_disable_configuration;
+       chipspecops->attach_to_chip=sja1000p_attach_to_chip;
+       chipspecops->release_chip=sja1000p_release_chip;
        chipspecops->set_btregs=sja1000p_set_btregs;
        chipspecops->start_chip=sja1000p_start_chip;
        chipspecops->stop_chip=sja1000p_stop_chip;
        chipspecops->irq_handler=sja1000p_irq_handler;
+       chipspecops->irq_accept=NULL;
        return 0;
 }