www.pudn.com > canbus4linux.rar > sja1000.c


/*
 * sja1000.c
 * Copyright (c) 2001 Jürgen Eder 
 *
 * A general chipset driver for CAN cards with SJA1000 (82C200 should work
 * in CAN 2.0A mode). To use this, the hardware driver is needed (e.g. can200par.o
 * or elektor_canpar.o)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
#define EXPORT_SYMTAB
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "trace.h"
#include "sja1000.h"
#include "canbus4linux.h"

#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif


int sja1000_set_baudrate(struct sja1000_admin *pSja1000Par, unsigned long baudrate);
int sja1000_set_baudrate_by_constant(struct sja1000_admin *pSja1000Par, unsigned long baudrate);
int sja1000_set_acceptance_filter(struct sja1000_admin *pSja1000Par, struct canbus_acceptance_filter *filter);
int sja1000_check_chipset(struct sja1000_admin *pSja1000Par);
int sja1000_activate_device(struct sja1000_admin *pSja1000Par);
int sja1000_init_device(struct sja1000_admin *pSja1000Par);
int sja1000_deactivate_device(struct sja1000_admin *pSja1000Par);
int sja1000_set_register(struct sja1000_admin *pSja1000Par, int addresse, unsigned int value);
int sja1000_get_register(struct sja1000_admin *pSja1000Par, int addresse, int *value);


#define NUM_SJA1000_DEVICES 10
static struct sja1000_admin sja1000_admin[NUM_SJA1000_DEVICES];

#define	SJA1000_DECLCHIP(x)	\
    struct sja1000_access * chip = &((x)->access); \
    void * chip_data = (x)->pDeviceParm; \
    do {} while (0)		// makes the user put ';' after it
 

#define	SJA1000_TEST_DECLCHIP(x) \
    struct sja1000_access * chip; \
    void * chip_data; \
    if (!(x)) \
        return -ENODEV; \
    chip = &((x)->access); \
    chip_data = (x)->pDeviceParm; \
    do {} while (0)		// makes the user put ';' after it

/***************************************************************************************/
static void sja1000_LockRegister(struct sja1000_admin *pSja1000Par)
{
	spin_lock_irqsave(&pSja1000Par->irq_lock,pSja1000Par->lock_flags);
}
/***************************************************************************************/
static void sja1000_UnLockRegister(struct sja1000_admin *pSja1000Par)
{
	spin_unlock_irqrestore(&pSja1000Par->irq_lock,pSja1000Par->lock_flags);
}
/***************************************************************************************/
static void sja1000_WriteRegister(struct sja1000_admin *pSja1000Par, u8 addr, u8 value)
{
 	SJA1000_DECLCHIP(pSja1000Par);
 	sja1000_LockRegister(pSja1000Par);
	chip->pWriteToRegister(chip_data, addr, value);
 	sja1000_UnLockRegister(pSja1000Par);
}
/***************************************************************************************/
static u8 sja1000_ReadRegister(struct sja1000_admin *pSja1000Par, u8 addr)
{
	u8 ret=0;
 	SJA1000_DECLCHIP(pSja1000Par);
 	sja1000_LockRegister(pSja1000Par);
	ret = chip->pReadFromRegister(chip_data, addr);
 	sja1000_UnLockRegister(pSja1000Par);
 	return ret;
}
/***************************************************************************************/
static void sja1000_WriteRegisterRR(struct sja1000_admin *pSja1000Par, u8 addr, u8 value)
{
 	SJA1000_DECLCHIP(pSja1000Par);
 	sja1000_LockRegister(pSja1000Par);
	chip->pWriteToRegister(chip_data, 0, chip->pReadFromRegister(chip_data,0) | 0x01);
	chip->pWriteToRegister(chip_data,  addr, value);
	chip->pWriteToRegister(chip_data, 0, chip->pReadFromRegister(chip_data,0) & 0x3e);
 	sja1000_UnLockRegister(pSja1000Par);
}
/***************************************************************************************/
static u8 sja1000_ReadRegisterRR(struct sja1000_admin *pSja1000Par, u8 addr)
{
	u8 ret=0;
 	SJA1000_DECLCHIP(pSja1000Par);
 	sja1000_LockRegister(pSja1000Par);
	chip->pWriteToRegister(chip_data, 0, chip->pReadFromRegister(chip_data,0) | 0x01);
	ret = chip->pReadFromRegister(chip_data, addr);
	chip->pWriteToRegister(chip_data, 0, chip->pReadFromRegister(chip_data,0) & 0x3e);
 	sja1000_UnLockRegister(pSja1000Par);
	return ret;
}
/***************************************************************************************/
int sja1000_open_device(struct sja1000_admin *pSja1000Par)
{
 	int ret;
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	ret = chip->pOpenCanDevice(chip_data);
 	sja1000_activate_device(pSja1000Par);
 	return ret;
}

/***************************************************************************************/
int sja1000_close_device(struct sja1000_admin *pSja1000Par)
{
 	int ret;
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	ret = chip->pCloseCanDevice(chip_data);
 	sja1000_deactivate_device(pSja1000Par);
 	return ret;
}
/***************************************************************************************/
int sja1000_init_device(struct sja1000_admin *pSja1000Par)
{
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	if (pSja1000Par->bCan_2B)
  	{
 		TRACE("Init Pelican");
 		sja1000_WriteRegisterRR(pSja1000Par,  0, 0x08);		// Acceptance Filter Mode: single
 		sja1000_WriteRegisterRR(pSja1000Par, 31, 0x80 | sja1000_ReadRegisterRR(pSja1000Par, 31)); // Pelican einschalten
 		sja1000_WriteRegisterRR(pSja1000Par,  4, 0xff);		// IRQ's
 		sja1000_WriteRegisterRR(pSja1000Par,  8, chip->output_control_register);		// Output Control
 		sja1000_WriteRegisterRR(pSja1000Par, 12,    0);		// error code capture
 		sja1000_WriteRegisterRR(pSja1000Par, 13,   96);		// error warning limit
 		sja1000_WriteRegisterRR(pSja1000Par, 14, 0x00);		// RX error counter
 		sja1000_WriteRegisterRR(pSja1000Par, 15, 0x00);		// TX error counter
 
 		sja1000_ReadRegister(pSja1000Par, 3);
 	}
 	else
 	{
 		TRACE("Init BasicCan");
 		sja1000_WriteRegisterRR(pSja1000Par, 31, 0x7f & sja1000_ReadRegisterRR(pSja1000Par, 31));	// Pelican ausschalten
 		sja1000_WriteRegisterRR(pSja1000Par,  0, 0x3f);		// Reset Request=1 + alle IRQs freigeben
 		sja1000_WriteRegisterRR(pSja1000Par,  8, chip->output_control_register);		// Output Control
 
 		sja1000_WriteRegister(pSja1000Par, 10, 0x25);		// Bit ID3 bis ID10
 		sja1000_WriteRegister(pSja1000Par, 11, 0x88);		// Bit ID0 bis ID2, RTR-Flag,  Data-Length-Code
	}
 
 	return 0;
}
/***************************************************************************************/
int sja1000_activate_device(struct sja1000_admin *pSja1000Par)
{
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	if (pSja1000Par->bCan_2B)
  	{
 		TRACE("Activate Pelican");
 		sja1000_WriteRegisterRR(pSja1000Par, 4, 0xff);	// IRQ's
 		sja1000_WriteRegisterRR(pSja1000Par, 8, chip->output_control_register);		// Output Control
 
 		sja1000_WriteRegister(pSja1000Par, 0, 0x00);		// Reset Request =0
 		sja1000_ReadRegister(pSja1000Par, 3);
  	}
 	else
 	{
 		TRACE("Activate BasicCan");
 		sja1000_WriteRegisterRR(pSja1000Par, 0, 0x3f);	// Reset Request=1 + alle IRQs freigeben
 		sja1000_WriteRegisterRR(pSja1000Par, 8, chip->output_control_register);		// Output Control
 
 		sja1000_WriteRegister(pSja1000Par, 0, 0x3e);		// Reset Request =0
 	}
 
 	return 0;
}

/***************************************************************************************/
int sja1000_deactivate_device(struct sja1000_admin *pSja1000Par)
{
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	if (pSja1000Par->bCan_2B)
  	{
 		TRACE("Activate Pelican");
 		sja1000_WriteRegisterRR(pSja1000Par, 4,0);		// IRQ's
 	}
 	else
 	{
 		TRACE("Activate BasicCan");
 		sja1000_WriteRegisterRR(pSja1000Par, 0,0);		// Reset Request=1 + alle IRQs freigeben
  	}
 
 	return 0;
}
/***************************************************************************************/
static int iSetSJA1000Baudrate(struct sja1000_admin *pSja1000Par)
{
 	u8 tmp;
	unsigned long wbaud;
	long bpr,ts1,ts2;
	
	int  ts2array[]={2,3,4,5,1,6,7,0};
	int  x;
	long testwert,neutest=50;

    INFO_TRACE("Calculating baudrate for frequency %d",pSja1000Par->access.chipset_frequency);
	wbaud = pSja1000Par->iBaudrate;
	if (wbaud < 5000) wbaud = 5000;
	if (wbaud > 2000000) wbaud = 2000000;
	pSja1000Par->iBaudrate = wbaud;
		
	testwert = pSja1000Par->access.chipset_frequency/(wbaud*2);
	while(neutest > 0)
	{
			for(x=0;x=0;ts1--)
				{
					if ((testwert % (ts1+ts2+3)) == 0)
					{
						bpr  = testwert/(ts1+ts2+3)-1;
						if ((bpr >= 0) && (bpr < 0x40))
						{
							bpr |= 0x40;    // SJW.0 setzen
							tmp = (u8)((ts2 << 4) + ts1);

							TRACE("%ld ts2 %ld ts1 %ld BPR0 0x%lx BPR1 0x%x",testwert,ts2, ts1, bpr,tmp);
 							sja1000_WriteRegisterRR(pSja1000Par, 6, (u8)bpr);
 							sja1000_WriteRegisterRR(pSja1000Par, 7, tmp);
							return 1;
						}
					}
				}
			}
			testwert++;
			neutest--;
	}

	TRACE("Can't set baudrate");
	return 0;
}

/***************************************************************************************/
int sja1000_set_baudrate(struct sja1000_admin *pSja1000Par, unsigned long baudrate)
{
	if(!pSja1000Par)
		return -ENODEV;

	pSja1000Par->iBaudrate = baudrate;
	if(!iSetSJA1000Baudrate(pSja1000Par))
	{
		return -EINVAL;
	}
	return 0;
}

/***************************************************************************************/
const unsigned long baudrate_list[]=
{
	20000,
	50000,
	100000,
	125000,
	150000,
	200000,
	500000,
	1000000,

	0
};

int sja1000_get_properties(struct sja1000_admin *pSja1000Par, struct canbus_properties *props)
{
	static const int basiccan[]=
	{
		CANBUS_CMD_ENTER_STANDBY,CANBUS_CMD_ABORT_TRANSMISSION,
		CANBUS_CMD_CLEAR_OVERRUN,CANBUS_CMD_LEAVE_STANDBY,0
	};

	static const int pelican[]=
	{
		CANBUS_CMD_ENTER_STANDBY,CANBUS_CMD_ABORT_TRANSMISSION,
		CANBUS_CMD_CLEAR_OVERRUN,CANBUS_CMD_LEAVE_STANDBY,
		CANBUS_CMD_SELF_RECEPTION_REQUEST,CANBUS_CMD_LISTEN_ON,
		CANBUS_CMD_LISTEN_OFF,0
	};

	int t;

	props->min = 20000;
	props->max = 1000000;
	props->chipset_flags = pSja1000Par->access.bCanChipsetFlags;
	props->number_baudrates = 0;
	props->number_registers = 128*2;

	/* This function is called by an application to get all provided commands. 
	 */
 	if(!pSja1000Par)
 		return -ENODEV;
 
 	if(pSja1000Par->bCan_2B)
  	{
 		for(t=0;pelican[t];t++)
 			props->commands[t] = pelican[t];
 		props->number_commands = t;
 	}
 	else
 	{
 		for(t=0;basiccan[t];t++)
 			props->commands[t] = basiccan[t];
 		props->number_commands = t;
 	}
  
 	for(t=0;baudrate_list[t] && (tbaudrates[t] = baudrate_list[t];
 	//props->number_baudrates = t;
  
  
 	return 0;
}

/***************************************************************************************/
int sja1000_set_register(struct sja1000_admin *pSja1000Par, int addresse, unsigned int value)
{
	int ret = -ENOSYS;

	/* The SJA1000 has 128 normal register and 128 'reset mode' register (in PELICAN mode) 
	 * To get a hardware abstraction in above layers, this function accepts following
	 * addresses:
	 * 0...7f = normal mode registers
	 * 80..ff = reset mode register 0...7f
	 */
	if(pSja1000Par)
	{
		if((addresse >= 0x80) && (addresse <= 0xff)) // RESET Mode ?
		{
			sja1000_WriteRegisterRR(pSja1000Par,addresse,value);
			ret = 0;
		}
		else if((addresse >= 0) && (addresse <= 0x7f))
		{
			sja1000_WriteRegister(pSja1000Par,addresse,value);
			ret = 0;
		}
		else		// todo: error number if out of addresse range
		{
			ret = 0;
		}

		// todo: error number if out of addresse range
	}
	return ret;
}

/***************************************************************************************/
int sja1000_get_register(struct sja1000_admin *pSja1000Par, int addresse, int *value)
{
	int ret = -ENOSYS;

	/* The SJA1000 has 128 normal register and 128 'reset mode' register (in PELICAN mode) 
	 * To get a hardware abstraction in above layers, this function accepts following
	 * addresses:
	 * 0...7f = normal mode registers
	 * 80..ff = reset mode register 0...7f
	 */
	if(pSja1000Par && value)
	{
		if((addresse >= 0x80) && (addresse <= 0xff)) // RESET Mode ?
		{
			*value = sja1000_ReadRegisterRR(pSja1000Par,addresse);
			ret = 0;
		}
		else if((addresse >= 0) && (addresse <= 0x7f))
		{
			*value = sja1000_ReadRegister(pSja1000Par,addresse);
			ret = 0;
		}
		else		// todo: error number if out of addresse range
		{
			*value = 0;
			ret = 0;
		}

	}
	return ret;
}

/***************************************************************************************/
int sja1000_set_can_mode(struct sja1000_admin *pSja1000Par, int can_2b)
{
 	if(!pSja1000Par)
 		return -ENODEV;
 
 	if((can_2b == 1) && !(pSja1000Par->access.bCanChipsetFlags & CANBUS_CFS_CAN_2_0_B))
  	{
 		pSja1000Par->bCan_2B = 0;
  		sja1000_init_device(pSja1000Par);
 		return -EINVAL;
  	}
 
 	pSja1000Par->bCan_2B = can_2b;
 	sja1000_init_device(pSja1000Par);
 	return 0;
}

/***************************************************************************************/
int sja1000_set_baudrate_by_constant(struct sja1000_admin *pSja1000Par, unsigned long constant)
{
	/* This function is only implemented for test and demonstration. A (chipset) driver
	 * usually implement only one function: xyz_set_baudrate() or xyz_set_baudrate_by_constant()
	 * but not both functions.
	 */
	if (constant >= sizeof(baudrate_list)/sizeof(unsigned long))
		return -ENODEV;
		
	return sja1000_set_baudrate(pSja1000Par, baudrate_list[constant]);
}

/***************************************************************************************/
int sja1000_set_acceptance_filter(struct sja1000_admin *pSja1000Par, struct canbus_acceptance_filter *filter)
{
 	unsigned long code = filter->code;
 	unsigned long mask = filter->mask;
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	if (pSja1000Par->bCan_2B)
 	{
 		sja1000_WriteRegisterRR(pSja1000Par, 16, (u8) (code >> 24) );		// ACC
 		sja1000_WriteRegisterRR(pSja1000Par, 17, (u8) (code >> 16) );		// ACC
 		sja1000_WriteRegisterRR(pSja1000Par, 18, (u8) (code >>  8) );		// ACC
 		sja1000_WriteRegisterRR(pSja1000Par, 19, (u8)  code        );		// ACC
 		sja1000_WriteRegisterRR(pSja1000Par, 20, (u8) (mask >> 24) );		// Mask
 		sja1000_WriteRegisterRR(pSja1000Par, 21, (u8) (mask >> 16) );		// Mask
 		sja1000_WriteRegisterRR(pSja1000Par, 22, (u8) (mask >>  8) );		// Mask
 		sja1000_WriteRegisterRR(pSja1000Par, 23, (u8)  mask        );		// Mask
 	}
 	else
  	{
 		sja1000_WriteRegisterRR(pSja1000Par,  4, (u8) (code>>3));	// Acceptance Code schreiben
 		sja1000_WriteRegisterRR(pSja1000Par,  5, (u8) (mask>>3));	// Acceptance Mask schreiben
  	}
 
 	return 0;
}

/***************************************************************************************/
int sja1000_set_command(struct sja1000_admin *pSja1000Par, int command)
{
  	struct canbus_event ev;
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	TRACE("sja1000_set_command CAN 2.0A = %d",pSja1000Par->bCan_2B);
 	if(!pSja1000Par->bCan_2B) switch(command)   // BASIC CAN Modus
  	{
 	case CANBUS_CMD_ENTER_STANDBY:
 		sja1000_WriteRegister(pSja1000Par, 1,0x10);
 		ev.event = CANBUS_EVENT_ENTERING_STANDBY;
 		if(pSja1000Par->isr)
  		{
 			(*pSja1000Par->isr)(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  		}
 		break;
 
 	case CANBUS_CMD_LEAVE_STANDBY:
 		sja1000_WriteRegister(pSja1000Par, 1,~0x10 & sja1000_ReadRegister(pSja1000Par,1));
 		break;
 
 	case CANBUS_CMD_ABORT_TRANSMISSION:
    	sja1000_WriteRegister(pSja1000Par, 1,0x02);
 		sja1000_ReadRegister(pSja1000Par, 3);
 		break;
 
 	case CANBUS_CMD_CLEAR_OVERRUN:
 		sja1000_WriteRegister(pSja1000Par, 1,0x08);
 		break;
 
 	default:
 		return -EINVAL;
 	}
 	else switch(command)						// Pelican Modus
 	{
 	case CANBUS_CMD_ENTER_STANDBY:
 		sja1000_WriteRegister(pSja1000Par, 0,0x10 |  sja1000_ReadRegister(pSja1000Par,0));
 		ev.event = CANBUS_EVENT_ENTERING_STANDBY;
 		if(pSja1000Par->isr)
 		{
 			(*pSja1000Par->isr)(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 		}
 		break;
 
 	case CANBUS_CMD_LEAVE_STANDBY:
 		sja1000_WriteRegister(pSja1000Par, 0,~0x10 & sja1000_ReadRegister(pSja1000Par,0));
 		break;
 
 	case CANBUS_CMD_ABORT_TRANSMISSION:
    	sja1000_WriteRegister(pSja1000Par, 1,0x02);
 		sja1000_ReadRegister(pSja1000Par, 3);
 		break;
 
 	case CANBUS_CMD_CLEAR_OVERRUN:
 		sja1000_WriteRegister(pSja1000Par, 1,0x08);
 		break;
 
 	case CANBUS_CMD_SELF_RECEPTION_REQUEST:
 		sja1000_WriteRegister(pSja1000Par, 1,0x10);
 		break;
 
 	case CANBUS_CMD_LISTEN_ON:
 		sja1000_WriteRegisterRR(pSja1000Par, 0,0x02 | sja1000_ReadRegister(pSja1000Par,0));
 		break;
 
 	case CANBUS_CMD_LISTEN_OFF:
 		sja1000_WriteRegisterRR(pSja1000Par, 0,~0x02 & sja1000_ReadRegister(pSja1000Par,0));
 		break;
 
 	default:
 		return -EINVAL;
  	}
 
 	return 0;
}

/***************************************************************************************/
int sja1000_transmit_data(struct sja1000_admin *pSja1000Par, struct canbus_transmit_data *trans)
{
	u8   i1,i2,len;

 	if( !(pSja1000Par && trans && (sja1000_check_chipset(pSja1000Par) >= 0)) )
 		return -ENODEV;
 
 	len= (trans->dlc > 8)?8:trans->dlc;
 
 	// Achtung! Die Routine wird auch aus der IRQ-Routine heraus aufgerufen
 	if (pSja1000Par->bCan_2B)
 	{
 		if (trans->fmt == CANBUS_TRANS_FMT_EXT)		// EFF
 		{
    			TRACE("TransmitToSJA1000 -1-");
 			i1 = len;
 			i1|= trans->rtr?0x40:0x00;
 			i1|= 0x80; // Modus: EFF
 			sja1000_WriteRegister(pSja1000Par, 16,i1);
 			i1 = (u8) ((trans->identifier & 0x1f) << 3);
 			sja1000_WriteRegister(pSja1000Par, 20,i1);
 			i1 = (u8) ((trans->identifier >> 5) & 0xff);
 			sja1000_WriteRegister(pSja1000Par, 19,i1);
 			i1 = (u8) ((trans->identifier >> 13) & 0xff);
 			sja1000_WriteRegister(pSja1000Par, 18,i1);
 			i1 = (u8) ((trans->identifier >> 21) & 0xff);
 			sja1000_WriteRegister(pSja1000Par, 17,i1);
 			
 			for(i1=0;i1msg[i1]);
 
 			sja1000_WriteRegister(pSja1000Par, 1,0x01); // Daten senden (Transmission Request)
 		}
 		else										// SFF
 		{
 			// Identifier begrenzen auf 11 Bit (sonst wird später was falsches angezeigt)
    			TRACE("TransmitToSJA1000 -2-");
 			trans->identifier &= 0x7ff;  
 
 			i1 = len;
 			i1|= trans->rtr?0x40:0x00;
 			sja1000_WriteRegister(pSja1000Par, 16,i1);
 			i1 = (u8) ((trans->identifier & 7) << 5);
 			sja1000_WriteRegister(pSja1000Par, 18,i1);
 			i1 = (u8) ((trans->identifier >> 3) & 0xff);
 			sja1000_WriteRegister(pSja1000Par, 17,i1);
 			
 			for(i1=0;i1msg[i1]);
 			sja1000_WriteRegister(pSja1000Par, 1,0x01); // Daten senden (Transmission Request)
 		}
 	}
 	else	// CAN2A
 	{
 		// Identifier begrenzen auf 11 Bit (sonst wird später was falsches angezeigt)
    		TRACE("TransmitToSJA1000 -3-");
 		trans->identifier &= 0x7ff;  
 
 		i1 = (u8) ((trans->identifier >> 3) & 0xff);
 		i2 = (u8) (trans->identifier & 0x07) << 5;
 		i2|= trans->rtr?0x10:0x00;
 		i2|= len;
 	
 		sja1000_WriteRegister(pSja1000Par, 10,i1);
 		sja1000_WriteRegister(pSja1000Par, 11,i2);
 	
 		for(i1=0;i1msg[i1]);
 
 		sja1000_WriteRegister(pSja1000Par, 1,0x01); // Daten senden (Transmission Request)
 	}
 
 	return 0;
}

/***************************************************************************************/
int sja1000_test_device(struct sja1000_admin *pSja1000Par)
{
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	TRACE("sja1000_test_device");

 	// The Bit 0x01 in register 0x00 is never set
 	if (sja1000_ReadRegister(pSja1000Par, 0) & 0x01) 
 	{
 		return 0;
 	}
 
 	return 1;
}
/***************************************************************************************/
int sja1000_check_chipset(struct sja1000_admin *pSja1000Par)
{
 	SJA1000_TEST_DECLCHIP(pSja1000Par);
 
 	TRACE("checkSJA1000");
 	if (sja1000_ReadRegister(pSja1000Par, 0) & 0x01)   // Baustein wurde in der Zwischenzeit rückgesetzt
 	{
 		sja1000_init_device(pSja1000Par); 
 		return 0;
  	}
 
 	return 1;
}


/***************************************************************************************/
int PeliCanISR(struct sja1000_admin *pSja1000Par)
{                                                       // CSerialPort::HwIntProc
     u8 irq;
 	u8 status;
  	struct canbus_event ev;
  	unsigned long id;
  	int   t;
 
  	TRACE("Pelican IRQ");
 	irq = sja1000_ReadRegister(pSja1000Par, 3); // Interrupt-Register lesen
  	if (!(irq & 0xff))
  		return 0;
  
  	TRACE("IRQ wird bearbeitet");
 	if(!(pSja1000Par->isr))
 		return 1;
 
 	if (irq & 0x01)				// Receive Interrupt
  	{
 		// Fülle Info-Struktur
 		TRACE("Receive IRQ");
 		ev.event = CANBUS_EVENT_RECEIVED;
 		status = sja1000_ReadRegister(pSja1000Par, 16);
 		if (status & 0x80) // Extended Frame Format (EFF)
 		{
 			ev.data.fmt = CANBUS_TRANS_FMT_EXT;
 			id = sja1000_ReadRegister(pSja1000Par, 17);
 			id = (id << 8) + sja1000_ReadRegister(pSja1000Par, 18);
 			id = (id << 8) + sja1000_ReadRegister(pSja1000Par, 19);
 			id = (id << 8) + sja1000_ReadRegister(pSja1000Par, 20);
 			id = id >> 3;
 			for(t=0;t<8;t++)
  			{
 				ev.data.msg[t] = sja1000_ReadRegister(pSja1000Par, 21+t);
  			}
  		}
 		else	// Standard Frame Format (SFF)
  		{
 			ev.data.fmt = CANBUS_TRANS_FMT_STD;
 			id = sja1000_ReadRegister(pSja1000Par, 17);
 			id = (id << 8) + sja1000_ReadRegister(pSja1000Par, 18);
 			id = id >> 5;
 			for(t=0;t<8;t++)
  			{
 				ev.data.msg[t] = sja1000_ReadRegister(pSja1000Par, 19+t);
  			}
  		}
 		ev.data.identifier = id;
 		ev.data.rtr = (status & 0x40) >> 6;
 		ev.data.dlc = (status & 0x0f);
 		sja1000_WriteRegister(pSja1000Par, 1,0x04); // ReleaseReceiveBuffer (Rx Buffer wird dadurch ungültig)
 
		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 	}
 
 	if (irq & 0x02)				// Transmit Interrupt
 	{
 		TRACE("Transmit IRQ");
 		ev.event = CANBUS_EVENT_TRANSMITTED;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
	}
 
 	if (irq & 0x04)				// Error Warning Interrupt
 	{
 		TRACE("Error Warning IRQ");
 		//sja1000_WriteRegister(pSja1000Par, 1,0x0e);                 // Release Receive Buffer + ClearDataOverrun + AbortTransmission (danach erfolgt ein Transmit-IRQ)
 		//sja1000_WriteRegister(pSja1000Par, 0, ~0x01 & sja1000_ReadRegister(pSja1000Par,0));       // resetMode löschen
 		ev.event = CANBUS_EVENT_WARNING;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 	}
 
 	if (irq & 0x08)				// Overrun Interrupt
 	{
 		TRACE("Overrun IRQ");
 		sja1000_WriteRegister(pSja1000Par, 1,0x0c); // Release Receive Buffer + ClearDataOverrun
 		ev.event = CANBUS_EVENT_OVERRUN;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 	}
 
 	if (irq & 0x10)				// WakeUp Interrupt
 	{
 		TRACE("WakeUp IRQ");
 		ev.event = CANBUS_EVENT_LEAVING_STANDBY;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  	}
 
 	if (irq & 0x20)				// Error Passive Interrupt
 	{
 		TRACE("Error passive IRQ");
 		ev.event = CANBUS_EVENT_PASSIVE;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 	}
 
 	if (irq & 0x40)				// Arbitration lost Interrupt
 	{
 		TRACE("Arbitration lost IRQ");
 		ev.event = CANBUS_EVENT_ARBITRATION_LOST;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 	}
 
 	if (irq & 0x80)				// Error Passive Interrupt
 	{
 		TRACE("Buserror IRQ");
 		sja1000_WriteRegister(pSja1000Par, 1,0x0e);                 // Release Receive Buffer + ClearDataOverrun + AbortTransmission (danach erfolgt ein Transmit-IRQ)
 		sja1000_WriteRegister(pSja1000Par, 0, ~0x01 & sja1000_ReadRegister(pSja1000Par,0));       // resetMode löschen
 		ev.event = CANBUS_EVENT_BUS_ERROR;
 
 		pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
 	}
 
 	return 1;		// TRUE = IRQ wurde bedient
}

/***************************************************************************************/
int BasicCanISR(struct sja1000_admin *pSja1000Par)
{
    u8 irq;
	u8 status;
	struct canbus_event ev;
	int   t;

	irq = sja1000_ReadRegister(pSja1000Par, 3);                                                // Interrupt-Register lesen
	TRACE("BasicCan IRQ 0x%x",irq);
	if (!(irq & 0x1f))
		return 0;

	TRACE("IRQ wird bearbeitet");
	if(pSja1000Par->isr)
	{
 		if (irq & 0x01)			// Receive Interrupt
  		{
  			TRACE("Receive IRQ");
  			ev.event = CANBUS_EVENT_RECEIVED;
 			ev.data.identifier = sja1000_ReadRegister(pSja1000Par, 20);
 			status = sja1000_ReadRegister(pSja1000Par, 21);
  			ev.data.fmt = CANBUS_TRANS_FMT_STD;
  			ev.data.identifier = (ev.data.identifier << 3) + ((status & 0xe0)>>5);
  			ev.data.rtr = (status & 0x10) >> 4;
  			ev.data.dlc = (status & 0x0f);
  			for(t=0;(t<8) && (tisr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  		}
 
 		if (irq & 0x02)			// Transmit Interrupt
  		{
  			TRACE("Transmit IRQ");
  			ev.event = CANBUS_EVENT_TRANSMITTED;
 
 			pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  		}
 
 		if (irq & 0x04)			// Error Interrupt
  		{
  			TRACE("Error IRQ");
 			sja1000_WriteRegister(pSja1000Par, 1,0x0e);                 // Release Receive Buffer + ClearDataOverrun + AbortTransmission (danach erfolgt ein Transmit-IRQ)
 			status = sja1000_ReadRegister(pSja1000Par, 0);             // Status einlesen
  			status = status & 0xfe; // ResetMode löschen
 			sja1000_WriteRegister(pSja1000Par, 0,status);       
  			ev.event = CANBUS_EVENT_BUS_ERROR;
 
 			pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  		}
 
 		if (irq & 0x08)			// Overrun Interrupt
  		{
  			TRACE("Overrun IRQ");
 			sja1000_WriteRegister(pSja1000Par, 1,0x0c); // Release Receive Buffer + ClearDataOverrun
  			ev.event = CANBUS_EVENT_OVERRUN;
 
 			pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  		}
 
 		if (irq & 0x10)			// WakeUp Interrupt
  		{
  			TRACE("WakeUp IRQ");
  			ev.event = CANBUS_EVENT_LEAVING_STANDBY;
 
 			pSja1000Par->isr(pSja1000Par->pCanBusParm, pSja1000Par->pCanBusParm, &ev);
  		}
  	}
  	else    // Setze nur die Bits zurück
  	{
 		if (irq & 0x01)				// Receive Interrupt
  		{
 			sja1000_WriteRegister(pSja1000Par, 1,0x04); // ReleaseReceiveBuffer (Rx Buffer wird dadurch ungültig)
  		}
 
 		if (irq & 0x04)				// Error Interrupt
  		{
 			sja1000_WriteRegister(pSja1000Par, 1,0x0e);                 // Release Receive Buffer + ClearDataOverrun + AbortTransmission (danach erfolgt ein Transmit-IRQ)
 			status = sja1000_ReadRegister(pSja1000Par, 0);             // read state
  			status = status & 0xfe; // clear ResetMode
 			sja1000_WriteRegister(pSja1000Par, 0,status);       
  		}
 
 		if (irq & 0x08)				// Overrun Interrupt
  		{
 			sja1000_WriteRegister(pSja1000Par, 1,0x0c); // Release Receive Buffer + ClearDataOverrun
  		}
  	}
 
 	return 1;		// TRUE = IRQ was served
}

/***************************************************************************************/
/*
int sja1000_interrupt(void *pSpecificPar, struct sja1000_admin *pSja1000Par)
{
	int ret=0;
	int x=30;

	if(!pSja1000Par)
		return 0;

//  HMM: Rubini's linux device drivers has erroneous statement about spin_trylock return value
//	the right treatment is as follows: 0 - failed, non-0 got lock (rubini: 0 - got lock)
//	see Linux Device Drivers 2nd edition, page 282.


//	XTRACE("InterruptProcedure - before spin_trylock...");

	if (!spin_trylock(&pSja1000Par->irq_lock))	{
//		XTRACE("...xxx");
//		XTRACE("spin_is_locked: %i", spin_is_locked(&pSja1000Par->irq_lock));
		return 0;	// irq handling is disabled for this chip
	}

	TRACE("InterruptProcedure");
	if (pSja1000Par->bCan_2B)
	{
		while(x>0)
		{
			if(PeliCanISR(pSja1000Par))
				ret=1;
			else
				break;
			x--;
		}
	}
	else
	{
		while(x>0)
		{
			if(BasicCanISR(pSja1000Par))
				ret=1;
			else
				break;
			x--;
		}
	}

	spin_unlock(&pSja1000Par->irq_lock);
	return ret;
}
*/
int sja1000_interrupt(void *pSpecificPar, struct sja1000_admin *pSja1000Par)
{
	int ret=0;
	int x=30;

	if(!pSja1000Par)
		return 0;

	TRACE("InterruptProcedure");
	if (pSja1000Par->bCan_2B)
	{
		while(x>0)
		{
			if(PeliCanISR(pSja1000Par))
				ret=1;
			else
				break;
			x--;
		}
	}
	else
	{
		while(x>0)
		{
			if(BasicCanISR(pSja1000Par))
				ret=1;
			else
				break;
			x--;
		}
	}
	return ret;
}

/***************************************************************************************/
int sja1000_register_isr(struct sja1000_admin *pSja1000Par, canbus_isr pIsr, struct canbus_admin *pCanBusPar)
{
	TRACE("registering isr()");
	if(!pSja1000Par)
		return -EINVAL;

	pSja1000Par->isr = pIsr;
	pSja1000Par->pCanBusParm = pCanBusPar;
	return 0;
}

/***************************************************************************************/
int sja1000_unregister_isr(struct sja1000_admin *pSja1000Par)
{
	TRACE("unregistering isr()");
	if(!pSja1000Par)
		return -EINVAL;

	pSja1000Par->isr = 0;
	pSja1000Par->pCanBusParm = NULL;
	return 0;
}
/***************************************************************************************/
int sja1000_register_device(char *name, int version, void *pSpecificPar, struct sja1000_access *access, int prefered_min, int prefered_max)
{
	int t,p;
	char buffer[MAX_DEVICE_NAME_LENGTH*2];
	
	TRACE("registering can device: %s",name);
	for(t=0;tpRegisterIsr) 
				(access->pRegisterIsr)(pSpecificPar, sja1000_interrupt, &sja1000_admin[t]);
			sja1000_admin[t].in_use = 1;

 			caccess.pRegisterIsr   = (canbus_registerIsr)	sja1000_register_isr;
 			caccess.pUnregisterIsr = (canbus_unregisterIsr)	sja1000_unregister_isr;
  
 			caccess.pOpen  = (canbus_open_device)  sja1000_open_device;
 			caccess.pClose = (canbus_close_device) sja1000_close_device;
 			caccess.pInit  = (canbus_init_device)  sja1000_init_device;
 
 			caccess.pSetBaudrate  = (canbus_set_baudrate)	sja1000_set_baudrate;
 			caccess.pGetProperty  = (canbus_get_properties)	sja1000_get_properties;
 			caccess.pSetRegister  = (canbus_set_register)	sja1000_set_register;
 			caccess.pGetRegister  = (canbus_get_register)	sja1000_get_register;
 			caccess.pSetCanMode   = (canbus_set_can_mode)	sja1000_set_can_mode;
 			caccess.pSetBaudrateByConstant = (canbus_set_baudrate_by_constant)
 															sja1000_set_baudrate_by_constant;
 			caccess.pSetAcceptanceFilter = (canbus_set_acceptance_filter)
 															sja1000_set_acceptance_filter;
 
 			caccess.pSetCommand   = (canbus_set_command)	sja1000_set_command;
 			caccess.pTransmitData = (canbus_transmit_data)	sja1000_transmit_data;
 			caccess.pTestDevice   = (canbus_test_device)	sja1000_test_device;

			sja1000_admin[t].canbus_admin_number = canbus4linux_register_device(buffer, CANBUS4LINUX_VERSION, &sja1000_admin[t], &caccess, prefered_min, prefered_max);
			TRACE("sja1000_register_device() - finished");
			return t;
		}
	}
	
	return -1;
}

/***************************************************************************************/
int sja1000_unregister_device(int can_num)
{
 	if (sja1000_admin[can_num].in_use == 0)
 		return 0;
 
 	TRACE("unregistering can device: %s",sja1000_admin[can_num].cDeviceName);
 	sja1000_admin[can_num].canbus_admin_number = canbus4linux_unregister_device(sja1000_admin[can_num].canbus_admin_number);
 	if (sja1000_admin[can_num].access.pUnregisterIsr)
 		(sja1000_admin[can_num].access.pUnregisterIsr)(sja1000_admin[can_num].pDeviceParm);
 
 	memset(&sja1000_admin[can_num],0,sizeof(struct sja1000_admin));
	return 0;
}

/***************************************************************************************/
int init_module(void)
{
	TRACE("init_module()");
	memset(sja1000_admin,0,sizeof(sja1000_admin));
  	return 0;
}

/***************************************************************************************/
void cleanup_module(void)
{
  	TRACE("cleanup");
}

/***************************************************************************************/
EXPORT_SYMBOL(sja1000_unregister_device);
EXPORT_SYMBOL(sja1000_register_device);
MODULE_AUTHOR("Juergen Eder  ");
MODULE_DESCRIPTION("SJA1000 chipset driver");