📄 irq.c
字号:
/* irq.c * Linux CAN-bus device driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl * This software is released under the GPL-License. * Version 0.7 6 Aug 2001 */#include <linux/autoconf.h>#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)#define MODVERSIONS#endif#if defined (MODVERSIONS)#include <linux/modversions.h>#endif #include <linux/sched.h>#include <linux/version.h>#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))#include <asm/spinlock.h>#else#include <linux/spinlock.h>#endif#include "../include/main.h"#include "../include/irq.h"#include "../include/i82527.h"#include "../include/sja1000.h"void i82527_irq_rtr_handler(void);void sja1000_irq_read_handler(void);void sja1000_irq_write_handler(void);void (*put_reg)(unsigned char data, unsigned long address);unsigned (*get_reg)(unsigned long address);struct chip_t *chip=NULL;struct candevice_t *device=NULL;unsigned object=0,irq_register=0;unsigned long msgbase=0;struct canfifo_t *fifo=NULL;unsigned long message_id=0;struct rtr_id *rtr_search;inline void i82527_irq_write_handler(void){ put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0); fifo->tx_readp++; if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) fifo->tx_readp = fifo->buf_tx_entry; if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty fifo->tx_in_progress = 0; if (waitqueue_active(&fifo->writeq)) { chip->msgobj[object]->ret = 0; wake_up_interruptible(&fifo->writeq); } return; } if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object], fifo->tx_readp)) { if (waitqueue_active(&fifo->writeq)) { chip->msgobj[object]->ret = -1; wake_up_interruptible(&fifo->writeq); return; } } if (chip->chipspecops->send_msg(chip, chip->msgobj[object], fifo->tx_readp)) { if (waitqueue_active(&fifo->writeq)) { chip->msgobj[object]->ret = -1; wake_up_interruptible(&fifo->writeq); return; } } }inline void i82527_irq_read_handler(void){ int i=0, tmp=1 ; while (tmp) { put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase + iMSGCTL1); put_reg((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase + iMSGCTL0); fifo->rx_writep->length =(get_reg(msgbase+iMSGCFG) & 0xf0) >> 4; fifo->rx_writep->id = message_id; for (i=0; i < fifo->rx_writep->length; i++) fifo->rx_writep->data[i] = get_reg(msgbase+iMSGDAT0+i);//FIXME: Add buffer overflow check, currently it's silently over written! fifo->rx_writep++; if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH) fifo->rx_writep = fifo->buf_rx_entry; if (!((tmp=get_reg(msgbase + iMSGCTL1)) & NEWD_SET)) { break; } if (tmp & MLST_SET) CANMSG("Message lost!\n"); } if (waitqueue_active(&fifo->readq)) { wake_up_interruptible(&fifo->readq); }}void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs){ int id0=0, id1=0, id2=0, id3=0; chip=(struct chip_t *)dev_id; device=(struct candevice_t *)chip->hostdevice; put_reg=device->hwspecops->write_register; get_reg=device->hwspecops->read_register; if ( (chip->flags & SEGMENTED) != 0) irq_register = get_reg(chip->chip_base_addr+iIRQ+SPACING); else irq_register = get_reg(chip->chip_base_addr+iIRQ); while (irq_register) { if (irq_register == 0x01) { DEBUGMSG("Status register: 0x%x\n",get_reg(chip->chip_base_addr+iSTAT)); return; } if (irq_register == 0x02) object = 14; else object = irq_register-3; fifo=chip->msgobj[object]->fifo; msgbase=chip->msgobj[object]->obj_base_addr; if (get_reg(msgbase+iMSGCFG) & MCFG_DIR) { i82527_irq_write_handler(); } else { if (extended) { id0=get_reg(msgbase+iMSGID3); id1=get_reg(msgbase+iMSGID2)<<8; id2=get_reg(msgbase+iMSGID1)<<16; id3=get_reg(msgbase+iMSGID0)<<24; message_id=(id0|id1|id2|id3)>>3; } else { id0=get_reg(msgbase+iMSGID1); id1=get_reg(msgbase+iMSGID0)<<8; message_id=(id0|id1)>>5; } spin_lock(&hardware_p->rtr_lock); rtr_search=hardware_p->rtr_queue; while (rtr_search != NULL) { if (rtr_search->id == message_id) break; rtr_search=rtr_search->next; } spin_unlock(&hardware_p->rtr_lock); if ((rtr_search!=NULL) && (rtr_search->id==message_id)) i82527_irq_rtr_handler(); else i82527_irq_read_handler(); } if ( (chip->flags & SEGMENTED) != 0) irq_register=get_reg(chip->chip_base_addr+iIRQ+SPACING); else irq_register=get_reg(chip->chip_base_addr+iIRQ); } }void i82527_irq_rtr_handler(void){ short int i=0; put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0); put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1); spin_lock(&hardware_p->rtr_lock); rtr_search->rtr_message->id=message_id; rtr_search->rtr_message->length=(get_reg(msgbase + iMSGCFG) & 0xf0)>>4; for (i=0; i<rtr_search->rtr_message->length; i++) rtr_search->rtr_message->data[i]=get_reg(msgbase+iMSGDAT0+i); spin_unlock(&hardware_p->rtr_lock); if (waitqueue_active(&rtr_search->rtr_wq)) wake_up_interruptible(&rtr_search->rtr_wq);}void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs){ chip=(struct chip_t *)dev_id; device=(struct candevice_t *)chip->hostdevice; put_reg=device->hwspecops->write_register; get_reg=device->hwspecops->read_register; irq_register=get_reg(chip->chip_base_addr+SJAIR);// DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);// DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n",// get_reg(chip->chip_base_addr+SJASR)); if ((irq_register & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0) return; fifo=chip->msgobj[0]->fifo; msgbase=chip->msgobj[0]->obj_base_addr; if ((irq_register & IR_RI) != 0) sja1000_irq_read_handler(); if ((irq_register & IR_TI) != 0) sja1000_irq_write_handler(); 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", get_reg(chip->chip_base_addr+SJASR), irq_register); chip->msgobj[0]->ret=-1; if (waitqueue_active(&fifo->writeq)) wake_up_interruptible(&fifo->writeq); if (waitqueue_active(&fifo->readq)) wake_up_interruptible(&fifo->readq); } return;}void sja1000_irq_read_handler(void){ int i=0, id=0, tmp=1; while (tmp) { id = get_reg(msgbase+SJARXID0) | (get_reg(msgbase+SJARXID1)<<8); fifo->buf_rx_entry[fifo->head].length = id & 0x0f; fifo->buf_rx_entry[fifo->head].flags = id&ID0_RTR ? MSG_RTR : 0; fifo->buf_rx_entry[fifo->head].timestamp = 0; fifo->buf_rx_entry[fifo->head].cob = 0; fifo->buf_rx_entry[fifo->head].id = id>>5; for (i=0; i<fifo->buf_rx_entry[fifo->head].length; i++) fifo->buf_rx_entry[fifo->head].data[i]=get_reg(msgbase + SJARXDAT0 + i); put_reg(CMR_RRB,msgbase+SJACMR); fifo->head++; if (fifo->head >= MAX_BUF_LENGTH-1) fifo->head=0; tmp=(get_reg(msgbase+SJASR) & SR_RBS); } if (waitqueue_active(&fifo->readq)) wake_up_interruptible(&fifo->readq);}void sja1000_irq_write_handler(void){ fifo->tx_readp++; if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH) fifo->tx_readp = fifo->buf_tx_entry; if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty fifo->tx_in_progress = 0; if (waitqueue_active(&fifo->writeq)) { chip->msgobj[object]->ret = 0; wake_up_interruptible(&fifo->writeq); } return; } if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object], fifo->tx_readp)) { if (waitqueue_active(&fifo->writeq)) { chip->msgobj[object]->ret = -1; wake_up_interruptible(&fifo->writeq); return; } } if (chip->chipspecops->send_msg(chip, chip->msgobj[object], fifo->tx_readp)) { if (waitqueue_active(&fifo->writeq)) { chip->msgobj[object]->ret = -1; wake_up_interruptible(&fifo->writeq); return; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -