+========================================
+List of developers and code contributors
+========================================
+
+
Arnaud Westenberg, arnaud@wanadoo.nl
Original can-0.7.1 author, http://home.wanadoo.nl/arnaud/
Rewrite of LDDK based CAN driver to the simpler infrastructure
Michal Sojka, sojkam1@control.felk.cvut.cz
Work on VME support for Unicontrols V-CAN board
on the PowerPC PEP VMP1 board
+
+Jose Pascual josepascual@almudi.com
+ contributed printer port dongle SJA1000 support
+
+Michael Moedt xemc@yahoo.com
+ added support for OSCAR SJA1000 based card connected
+ to ARM LH7A400 SoC
+
+========================================
+List of companies and subjects
+who donated hardware to LinCAN project
+========================================
+
+BFAD GmbH & Co.KG
+http://www.bfad.de/
+ donated BfaD DIMM module CAN card
+
+PiKRON Ltd.
+ provided more ISA based cards
+
+Unicontrols a.s.
+http://www.unicontrols.cz/
+ provided PC-104, PCI and VME CAN boards
+ and VMP1 PowerPC based system
+
+Kvaser AB
+http://www.kvaser.com/
+ donated PCIcan 4xHS card
+
+Artificial Vision and Intelligent Vision Lab
+Dipartimento di Ingegneria dell'Informazione
+Universita' degli Studi di Parma
+http://vislab.ce.unipr.it/
+ donated EMS CPC-PCI card
+
lincan-0.2 version tested on many bords and 2.2, 2.4, 2.6 Linux
(Mar 2004) and RT-Linux enabled 2.4 Linux kernel
-lincan-0.3 possible SMP and HT deadlock fixed, driver can take
+lincan-0.2.8 possible SMP and HT deadlock fixed, driver can take
(Jul 2004) advantage of CMPXCHG instruction if present on CPU,
added support for CPC-PCI and PCAN-PCI cards,
messages timestamping implemented
- unican-pci for Unicontrols PCAN-PCI card
- unican-vme for Unicontrols VCAN card
- ems_cpcpci for EMS CPC-PCI card
+- pcan_dongle for PEAK's printer port dongle addapter
- oscar for SJA1000 based card connected to ARM LH7A400 SoC
- template, for yet unsupported hardware (you need to edit src/template.c)
- virtual, CAN channel for testing of software and driver without CAN hardware
/* These flags can be used for the canchip_t structure flags data entry */
-#define CHIP_CONFIGURED (1<<0)
-#define CHIP_SEGMENTED (1<<1)
-#define CHIP_IRQ_SETUP (1<<2)
-#define CHIP_IRQ_PCI (1<<3)
-#define CHIP_IRQ_VME (1<<4)
+#define CHIP_CONFIGURED (1<<0) /* chip is configured and prepared for communication */
+#define CHIP_SEGMENTED (1<<1) /* segmented access, ex: i82527 with 16 byte window*/
+#define CHIP_IRQ_SETUP (1<<2) /* IRQ handler has been set */
+#define CHIP_IRQ_PCI (1<<3) /* chip is on PCI board and uses PCI interrupt */
+#define CHIP_IRQ_VME (1<<4) /* interrupt is VME bus and requires VME bridge */
+#define CHIP_IRQ_CUSTOM (1<<5) /* custom interrupt provided by board or chip code */
+#define CHIP_IRQ_FAST (1<<6) /* interrupt handler only schedules postponed processing */
+
+#define CHIP_MAX_IRQLOOP 1000
/* System independent defines of IRQ handled state */
#define CANCHIP_IRQ_NONE 0
#define CANCHIP_IRQ_HANDLED 1
+#define CANCHIP_IRQ_STUCK 2
/* These flags can be used for the candevices_t structure flags data entry */
#define CANDEV_PROGRAMMABLE_IRQ (1<<0)
attrib_p=&attrib;
}
- if(chip->chipspecops->irq_handler){
+ if(chip->chipspecops->irq_handler && !(chip->flags & CHIP_IRQ_CUSTOM)){
int (*my_request_irq)(unsigned int vector, unsigned int (*rtl_handler)(unsigned int irq, struct pt_regs *regs));
#ifdef CAN_ENABLE_VME_SUPPORT
if ((chip->flags & CHIP_IRQ_VME) != 0)
{
if(chip->worker_thread)
pthread_delete_np(chip->worker_thread);
- if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+ if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)
+ && !(chip->flags & CHIP_IRQ_CUSTOM)) {
int (*my_free_irq)(unsigned int vector);
#ifdef CAN_ENABLE_VME_SUPPORT
if ((chip->flags & CHIP_IRQ_VME) != 0)
unsigned irq_register;
unsigned object;
struct msgobj_t *obj;
+ int loop_cnt=CHIP_MAX_IRQLOOP;
/*put_reg=device->hwspecops->write_register;*/
/*get_reg=device->hwspecops->read_register;*/
do {
+ if(!loop_cnt--) {
+ CANMSG("i82527_irq_handler IRQ %d stuck\n",irq);
+ return CANCHIP_IRQ_STUCK;
+ }
+
DEBUGMSG("i82527: iIRQ 0x%02x\n",irq_register);
if (irq_register == 0x01) {
i82527_irq_read_handler(chip, obj, object);
}
+
+ irq_register=i82527_seg_read_reg(chip, iIRQ);
- } while((irq_register=i82527_seg_read_reg(chip, iIRQ)) != 0);
+ } while(irq_register != 0);
return CANCHIP_IRQ_HANDLED;
}
candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
- candev->chip[chipnr]->flags |= CHIP_IRQ_VME; // I don't want setup call request_irq
+ candev->chip[chipnr]->flags |= CHIP_IRQ_CUSTOM; // I don't want setup call request_irq
// I'm going to do it through parport_register_device
}
return -1;
if(!chip->chipspecops->irq_handler)
return 0;
+ if(chip->flags & CHIP_IRQ_CUSTOM)
+ return 1;
if ((chip->flags & CHIP_IRQ_VME) == 0) {
if (request_irq(chip->chip_irq,can_default_irq_dispatch,SA_SHIRQ,DEVICE_NAME,chip))
void can_chip_free_irq(struct canchip_t *chip)
{
if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+ if(chip->flags & CHIP_IRQ_CUSTOM)
+ return;
+
if ((chip->flags & CHIP_IRQ_VME) == 0)
free_irq(chip->chip_irq, chip);
else {
{
unsigned irq_register;
struct msgobj_t *obj=chip->msgobj[0];
+ int loop_cnt=CHIP_MAX_IRQLOOP;
irq_register=can_read_reg(chip, SJAIR);
// DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);
if ((irq_register & (sjaIR_WUI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI)) == 0)
return CANCHIP_IRQ_NONE;
- if ((irq_register & sjaIR_RI) != 0)
- sja1000_irq_read_handler(chip, obj);
+ do {
+
+ if(!loop_cnt--) {
+ CANMSG("sja1000_irq_handler IRQ %d stuck\n",irq);
+ return CANCHIP_IRQ_STUCK;
+ }
+
+ if ((irq_register & sjaIR_RI) != 0)
+ sja1000_irq_read_handler(chip, obj);
- if ((irq_register & sjaIR_TI) != 0) {
- can_msgobj_set_fl(obj,TX_REQUEST);
- while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
- can_msgobj_clear_fl(obj,TX_REQUEST);
+ if ((irq_register & sjaIR_TI) != 0) {
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
- if (can_read_reg(chip, SJASR) & sjaSR_TBS)
- sja1000_irq_write_handler(chip, obj);
+ if (can_read_reg(chip, SJASR) & sjaSR_TBS)
+ sja1000_irq_write_handler(chip, obj);
- can_msgobj_clear_fl(obj,TX_LOCK);
- if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
+ }
}
- }
- if ((irq_register & (sjaIR_EI|sjaIR_DOI)) != 0) {
- // Some error happened
+ if ((irq_register & (sjaIR_EI|sjaIR_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;*/
+ 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;*/
+ }
}
- }
+ irq_register=can_read_reg(chip, SJAIR);
+
+ } while(irq_register & (sjaIR_WUI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI));
+
return CANCHIP_IRQ_HANDLED;
}
{
int irq_register, status, error_code;
struct msgobj_t *obj=chip->msgobj[0];
+ int loop_cnt=CHIP_MAX_IRQLOOP;
irq_register=can_read_reg(chip,SJAIR);
// DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);
return CANCHIP_IRQ_NONE;
}
- if ((irq_register & sjaIR_RI) != 0) {
- DEBUGMSG("sja1000_irq_handler: RI\n");
- sja1000p_read(chip,obj);
- obj->ret = 0;
- }
- if ((irq_register & sjaIR_TI) != 0) {
- DEBUGMSG("sja1000_irq_handler: TI\n");
- obj->ret = 0;
- can_msgobj_set_fl(obj,TX_REQUEST);
- while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
- can_msgobj_clear_fl(obj,TX_REQUEST);
-
- if (can_read_reg(chip, SJASR) & sjaSR_TBS)
- sja1000p_irq_write_handler(chip, obj);
-
- can_msgobj_clear_fl(obj,TX_LOCK);
- if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
- DEBUGMSG("TX looping in sja1000_irq_handler\n");
+ do {
+
+ if(!loop_cnt--) {
+ CANMSG("sja1000p_irq_handler IRQ %d stuck\n",irq);
+ return CANCHIP_IRQ_STUCK;
}
- }
- 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);
+
+ if ((irq_register & sjaIR_RI) != 0) {
+ DEBUGMSG("sja1000_irq_handler: RI\n");
+ sja1000p_read(chip,obj);
+ obj->ret = 0;
+ }
+ if ((irq_register & sjaIR_TI) != 0) {
+ DEBUGMSG("sja1000_irq_handler: TI\n");
+ obj->ret = 0;
+ can_msgobj_set_fl(obj,TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
+ can_msgobj_clear_fl(obj,TX_REQUEST);
+
+ if (can_read_reg(chip, SJASR) & sjaSR_TBS)
+ sja1000p_irq_write_handler(chip, obj);
+
+ can_msgobj_clear_fl(obj,TX_LOCK);
+ if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
+ DEBUGMSG("TX looping in sja1000_irq_handler\n");
+ }
+ }
+ 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);
// 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
obj->ret=-1;
- if(error_code == 0xd9) {
- obj->ret= -ENXIO;
- /* no such device or address - no ACK received */
- }
- if(obj->tx_retry_cnt++>MAX_RETR) {
- can_write_reg(chip, sjaCMR_AT, SJACMR); // cancel any transmition
- obj->tx_retry_cnt = 0;
- }
- if(status&sjaSR_BS) {
- CANMSG("bus-off, resetting sja1000p\n");
- can_write_reg(chip, 0, SJAMOD);
- }
-
- 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;*/
+ if(error_code == 0xd9) {
+ obj->ret= -ENXIO;
+ /* no such device or address - no ACK received */
+ }
+ if(obj->tx_retry_cnt++>MAX_RETR) {
+ can_write_reg(chip, sjaCMR_AT, SJACMR); // cancel any transmition
+ obj->tx_retry_cnt = 0;
+ }
+ if(status&sjaSR_BS) {
+ CANMSG("bus-off, resetting sja1000p\n");
+ can_write_reg(chip, 0, SJAMOD);
+ }
+
+ 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;*/
+ }
+
+ } else {
+ obj->tx_retry_cnt=0;
}
- } else {
- obj->tx_retry_cnt=0;
- }
+ irq_register=can_read_reg(chip,SJAIR);
+
+ } while(irq_register & (sjaIR_BEI|sjaIR_EPI|sjaIR_DOI|sjaIR_EI|sjaIR_TI|sjaIR_RI));
return CANCHIP_IRQ_HANDLED;
}