X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/97078fff5202521b758c9081d75580880417a123..11132ea490f9e860744ee4f851c67e7fb4444231:/lincan/src/sja1000.c diff --git a/lincan/src/sja1000.c b/lincan/src/sja1000.c index 0955c76..bca1fec 100644 --- a/lincan/src/sja1000.c +++ b/lincan/src/sja1000.c @@ -1,25 +1,24 @@ /* sja1000.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * 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 0.6 18 Sept 2000 + * Version lincan-0.2 9 Jul 2003 */ #include -#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS) -#define MODVERSIONS -#endif - -#if defined (MODVERSIONS) -#include -#endif +#include #include #include #include "../include/main.h" #include "../include/sja1000.h" +void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj); +void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj); + int sja1000_enable_configuration(struct chip_t *chip) { int i=0; @@ -194,48 +193,31 @@ int sja1000_baud_rate(struct chip_t *chip, int rate, int clock, int sjw, int sja1000_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) { int i; - struct canfifo_t *fifo = chip->msgobj[0]->fifo; - int id; + i=can_read_reg(chip,SJASR); if (!(i&SR_RBS)) { //Temp - for (i=0; i<0x20; i++) - CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i)); - return 0; + for (i=0; i<0x20; i++) + CANMSG("0x%x is 0x%x\n",i,can_read_reg(chip,i)); + return 0; } sja1000_start_chip(chip); - can_write_reg(chip, 0, SJACR); // disable interrupts for a moment -// TODO: this would be best sja1000_irq_read_handler(chip); -// now just duplicate the code. - do { - id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); - fifo->rx_writep->length = id & 0x0f; - fifo->rx_writep->flags = id&ID0_RTR ? MSG_RTR : 0; - fifo->rx_writep->timestamp = 0; - fifo->rx_writep->cob = 0; - fifo->rx_writep->id = id>>5; + // disable interrupts for a moment + can_write_reg(chip, 0, SJACR); - for (i=0; irx_writep->length; i++) - fifo->rx_writep->data[i]=can_read_reg(chip, SJARXDAT0 + i); + sja1000_irq_read_handler(chip, obj); - fifo->rx_writep++; - if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) - fifo->rx_writep = fifo->buf_rx_entry; - - can_write_reg(chip, CMR_RRB, SJACMR); - - } while (can_read_reg(chip, SJASR) & SR_RBS); - -// enable interrupts + // enable interrupts can_write_reg(chip, CR_OIE | CR_EIE | CR_TIE | CR_RIE, SJACR); return 1; } -#define MAX_TRANSMIT_WAIT_LOOPS 200 +#define MAX_TRANSMIT_WAIT_LOOPS 10 + int sja1000_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { @@ -349,6 +331,138 @@ int sja1000_config_irqs(struct chip_t *chip, short irqs) return -ENOSYS; } + +irqreturn_t sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned irq_register; + struct chip_t *chip=(struct chip_t *)dev_id; + struct msgobj_t *obj=chip->msgobj[0]; + + irq_register=can_read_reg(chip, SJAIR); +// DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register); +// DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n", +// can_read_reg(chip, SJASR)); + + if ((irq_register & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) + return IRQ_NONE; + + if ((irq_register & IR_RI) != 0) + sja1000_irq_read_handler(chip, obj); + + if ((irq_register & IR_TI) != 0) { + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if (can_read_reg(chip, SJASR) & SR_TBS) + sja1000_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + } + } + + if ((irq_register & (IR_EI|IR_DOI)) != 0) { + // Some error happened +// FIXME: chip should be brought to usable state. Transmission cancelled if in progress. +// Reset flag set to 0 if chip is already off the bus. Full state report + CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n", + can_read_reg(chip, SJASR), irq_register); + obj->ret=-1; + + if(obj->tx_slot){ + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_BUS); + /*canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL;*/ + } + } + + return IRQ_HANDLED; +} + +void sja1000_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj) +{ + int i=0, id=0; + + do { + id = can_read_reg(chip, SJARXID0) | (can_read_reg(chip, SJARXID1)<<8); + obj->rx_msg.length = id & 0x0f; + obj->rx_msg.flags = id&ID0_RTR ? MSG_RTR : 0; + obj->rx_msg.timestamp = 0; + obj->rx_msg.cob = 0; + obj->rx_msg.id = id>>5; + + for (i=0; irx_msg.length; i++) + obj->rx_msg.data[i]=can_read_reg(chip, SJARXDAT0 + i); + + can_write_reg(chip, CMR_RRB, SJACMR); + + canque_filter_msg2edges(obj->qends, &obj->rx_msg); + } while(can_read_reg(chip, SJASR) & SR_RBS); +} + +void sja1000_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj) +{ + int cmd; + + if(obj->tx_slot){ + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + } + + cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot); + if(cmd<0) + return; + + if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) { + obj->ret = -1; + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP); + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + return; + } + if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) { + obj->ret = -1; + canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND); + canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); + obj->tx_slot=NULL; + return; + } +} + +/** + * sja1000_wakeup_tx: - wakeups TX processing + * @chip: pointer to chip state structure + * @obj: pointer to message object structure + * + * Return Value: negative value reports error. + * File: src/sja1000.c + */ +int sja1000_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) +{ + /* dummy lock to prevent preemption fully portable way */ + spinlock_t dummy_lock; + + /* preempt_disable() */ + spin_lock_init(&dummy_lock); + spin_lock(&dummy_lock); + + set_bit(OBJ_TX_REQUEST,&obj->flags); + while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){ + clear_bit(OBJ_TX_REQUEST,&obj->flags); + + if (can_read_reg(chip, SJASR) & SR_TBS) + sja1000_irq_write_handler(chip, obj); + + clear_bit(OBJ_TX_LOCK,&obj->flags); + if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break; + } + + /* preempt_enable(); */ + spin_unlock(&dummy_lock); + return 0; +} + int sja1000_register(struct chipspecops_t *chipspecops) { chipspecops->chip_config = sja1000_chip_config; @@ -362,6 +476,7 @@ int sja1000_register(struct chipspecops_t *chipspecops) chipspecops->pre_write_config = sja1000_pre_write_config; chipspecops->send_msg = sja1000_send_msg; chipspecops->check_tx_stat = sja1000_check_tx_stat; + chipspecops->wakeup_tx=sja1000_wakeup_tx; chipspecops->remote_request = sja1000_remote_request; chipspecops->enable_configuration = sja1000_enable_configuration; chipspecops->disable_configuration = sja1000_disable_configuration;