Example #1
0
/*
 * PCM3680  Remarks
 *
 * Adresses used related to the Basde adress (set by dip switches) 
 * Base address (hex)      CAN controller
 * base:0000h - base:00FFh Basic- Port 1
 * base:0100h - base:01FFh HW reset Basic - Port 1
 * base:0200h - base:02FFh Basic- Port 2
 * base:0300h - base:03FFh HW reset Basic - Port 2
 * base:0400h - base:0FFFh Not used
 * 
 * Each CAN channel uses 0x200 bytes
 */
int CAN_VendorInit (int minor)
{
    DBGin("CAN_VendorInit");
    can_range[minor] = 0x200;
    

    /* Some LINUX systems, e.g. the PIP10 I tested on,
     * locate already the memory using the information
     * provided in the "Option ROM"
     * The memory is marked as "Adapter-ROM" in /proc/iomem.
     * In this case the drive should not try to allocate the IO mem */

#if !defined(PC104_OPTION_ROM)
    /* Request the controllers address space */
    if(NULL == request_mem_region(Base[minor], can_range[minor], "CAN-IO")) {
	DBGprint(DBG_DATA,("Request_mem-Region CAN-IO failed at 0x%x\n",
		Base[minor]));
	return -EBUSY;
    }
#endif

    controller_available(Base[minor], 1);

    can_base[minor] = ioremap(Base[minor], can_range[minor]);
    /* now the virtual address can be used for the register access macros */


    if( Base[minor] & 0x200 ) {
	    /* printk("Resetting Advantech Pcm-3680 [contr 1]\n"); */
	    /* perform HW reset 2. contr*/
	    writeb(0xff, can_base[minor] + 0x300);
    } else {
	    /* printk("Resetting Advantech Pcm-3680 [contr 0]\n"); */
	    /* perform HW reset 1. contr*/
	    writeb(0xff, can_base[minor] + 0x100);
    }
    mdelay(100);



    if( IRQ[minor] > 0 || IRQ[minor] > MAX_IRQNUMBER ){
        int err;
	err = request_irq( IRQ[minor], CAN_Interrupt, SA_SHIRQ, 
				"Can", &Can_minors[minor]);
        if( !err ){
	    DBGprint(DBG_BRANCH,("Requested IRQ: %d @ 0x%lx",
				    IRQ[minor], (unsigned long)CAN_Interrupt));
	    IRQ_requested[minor] = 1;
	} else {
	    release_mem_region(Base[minor], can_range[minor]);
	    DBGout(); return -EBUSY;
	}
    } else {
	/* Invalid IRQ number in /proc/.../IRQ */
	release_mem_region(Base[minor], can_range[minor]);
	DBGout(); return -EBUSY;
    }
    DBGout(); return 0;
}
Example #2
0
/* change the bit timings of the selected CAN channel */
int CAN_SetTiming (int board, int baud)
{
/* int custom=0; */
BTR_TAB_TOUCAN_T * table = (BTR_TAB_TOUCAN_T*)can_btr_tab_toucan;

    DBGin("CAN_SetTiming");
    DBGprint(DBG_DATA, ("baud[%d]=%d", board, baud));
    /* enable changing of bit timings */
    CANsetw(board, canmcr, CAN_MCR_HALT);
    /* search for data from table */
    while(1) {
        if (table->rate == 0 || table->rate == baud) {
    	    break;
    	}
    	table++;
    }
    if (table->rate == 0) {
	/* try to use baud  as custom specific bit rate
	 * not implemented yet
	 */
	return -ENXIO;
    }

    /*
     * Set Timing Register values.
     * Initialize the bit timing parameters PROPSEG, PSEG1, PSEG2 and RJW
     * in control registers 1 and 2.
     *
     * The FlexCAN module uses three 8-bit registers to set-up
     * the bit timing parameters required by the CAN protocol.
     * Control registers 1 and 2 contain the PROPSEG, PSEG1, PSEG2
     * and RJW fields which allow the user to configure
     * the bit timing parameters.
     * The prescaler divide register (PRESDIV) allows the user to select
     * the ratio used to derive the S-Clock from the system clock.
     * The time quanta clock operates at the S-clock frequency.
     */
    CANout(board, presdiv, table->presdiv);
    CANout(board, canctrl2, ((table->pseg1 << 3)+ table->pseg2));
    CANout(board, canctrl1, (
    	  0		/* SAMP = 0 , 0/0x80		*/	
    	+ 0		/* LOOP = 0 , 0/0x40		*/	
    	+ 0		/* TSYNC= 0 , 0/0x20		*/
    	+ 0		/* LBUF = 0 , 0/0x10		*/
    	+ 0		/* RSVD = 0 , 0/0x08		*/
    	+ table->propseg)
    	);

    /*
     * Stay in configuration mode; a call to Start-CAN() is necessary to
     * activate the CAN controller with the new bit rate
     */
    DBGprint(DBG_DATA,("canctrl2=0x%x presdiv=0x%x",
    		CANin(board, canctrl2), CANin(board, presdiv)) );

    DBGout();
    return 0;
}
int can_Config(
	struct inode *inode,
	int target,
	unsigned long val1,
	unsigned long val2
	)
{
unsigned int minor = MINOR(inode->i_rdev);	

    switch(target) {
      case CONF_ACC:
    DBGprint(DBG_DATA,("mask = 0x%lx, code = 0x%lx", val1, val2));
	   AccMask[minor] = val1;
	   AccCode[minor] = val2;
	   CAN_SetMask(minor, AccCode[minor], AccMask[minor]);		
	   break;
      case CONF_ACCM:
    DBGprint(DBG_DATA,("acc_mask=0x%lx", val1));
	   AccMask[minor] = val1;
	   CAN_SetMask(minor, AccCode[minor], AccMask[minor]);		
	   break;
      case CONF_ACCC:
    DBGprint(DBG_DATA,("acc_code=0x%lx", val1));
	   AccCode[minor] = val1;
	   CAN_SetMask(minor, AccCode[minor], AccMask[minor]);		
	   break;
      case CONF_TIMING:
	   Baud[minor] = val1;
	   CAN_SetTiming(minor,(int) val1);   
	   break;                    
      case CONF_OMODE:
	   CAN_SetOMode( minor, (int) val1);
	   break;			
#if CAN_USE_FILTER
      case CONF_FILTER:
	   Can_FilterOnOff( minor, (int) val1 );
	   break;
      case CONF_FENABLE:
	   Can_FilterMessage( minor, (int) val1, 1);
	   break;
      case CONF_FDISABLE:
	   Can_FilterMessage( minor, (int) val1, 0);
	   break;
#endif
      default:
	    DBGout();
	    return(-EINVAL);
    }
    return 0;
}
Example #4
0
int Can_RequestIrq(int minor, int irq,
    irqreturn_t (*handler)(int, void *, struct pt_regs *))
{
int err=0;

    DBGin("Can_RequestIrq");
    /*

    int request_irq(unsigned int irq,			// interrupt number  
              void (*handler)(int, void *, struct pt_regs *), // pointer to ISR
		              irq, dev_id, registers on stack
              unsigned long irqflags, const char *devname,
              void *dev_id);

       dev_id - The device ID of this handler (see below).       
       This parameter is usually set to NULL,
       but should be non-null if you wish to do  IRQ  sharing.
       This  doesn't  matter when hooking the
       interrupt, but is required so  that,  when  free_irq()  is
       called,  the  correct driver is unhooked.  Since this is a
       void *, it can point to anything (such  as  a  device-speĀ­
       cific  structure,  or even empty space), but make sure you
       pass the same pointer to free_irq().

    */

    {
	int i;
	/* 19 Int vectors are used on Interrupt Controller 1 */
	for( i = 136; i < 155; i++) {
	    err = request_irq( i, handler, SA_INTERRUPT, "Can", &Can_minors[minor]);
	    if(err) {
    		DBGout();return err;
	    }
	}
    }
    if( !err ){
	/* printk("Requested IRQ[%d]: %d @ 0x%x", minor, irq, handler); */

/* Now the kernel has assigned a service to the Interruptvector,
   time to enable the hardware to generate an ISR.

   here should be used a generic function e.g. can_irqsetup(minor)
   and do whatever needed for the app. hardware
   to reduce #ifdef clutter
   */
	mcf_irqsetup();

	/* irq2minormap[irq] = minor; */

	/* irq2pidmap[irq] = current->pid; */
	DBGprint(DBG_BRANCH,("Requested IRQ: %d @ 0x%lx",
				irq, (unsigned long)handler));
	IRQ_requested[minor] = 1;
    }
    DBGout();return err;
}
Example #5
0
/* set value of the output control register
 * The register is not available, nothing happens here 
 * besides printing some debug information
 */
int CAN_SetOMode (int board, int arg)
{

    DBGin("CAN_SetOMode");
	DBGprint(DBG_DATA,("[%d] outc=0x%x", board, arg));

    DBGout();
    return 0;
}
Example #6
0
/* look if one of the receive message objects has something received */
int CAN_GetMessage (int board, canmsg_t *rx )
{
volatile unsigned int stat;
volatile unsigned int ctrl;
int i = 0;

    DBGin("CAN_GetMessage");
    stat = CANinw(board, estat);
    DBGprint(DBG_DATA,("0x%x: stat=0x%x iflag=0x%x imask=0x%x" ,
    			Base[board], stat,
    			CANinw(board, iflag),
    			CANinw(board, imask)));

    rx->flags  = 0;
    rx->length = 0;

    /* CAN_register_dump(); */
    /* CAN_object_dump(RECEIVE_STD_OBJ); */
    i = CANinw(board, iflag);
    if( i & (1 << RECEIVE_STD_OBJ)) {
	/* reading the control status word of the identified message
	 * buffer triggers a lock for that buffer.
	 * A new received message frame which maches the message buffer
	 * can not be written into this buffer while it is locked
	 */
        while (((ctrl = CAN_READ_CTRL(RECEIVE_STD_OBJ)) & (REC_CODE_BUSY << 4)) == (REC_CODE_BUSY << 4)) {
	    /* 20 cycles maximum wait */
	    /* printf1("CAN_int, rx REC_CODE_BUSY"); */
	}
	/* printk("message received 0x%x\n", ctrl); */
	rx->length = ctrl & 0x0f;
	rx->id =  CAN_READ_OID(RECEIVE_STD_OBJ);
	memcpy((void *)&rx->data[0],
	       (const void *)&(CAN_OBJ[RECEIVE_STD_OBJ].MSG0), 8);

	/* clear interrupts */
	/* Int is cleared when the CPU reads the intrerupt flag register iflag
	 * while the associated bit is set, and then writes it back as '1'
	 * (and no new event of the same type occurs
	 * between the read and write action.)
	 * ! This is opposit to the TouCAN module, where the iflag bit
	 * has to be written back with '0'
	 */
	CANsetw(board, iflag, (1 << RECEIVE_STD_OBJ));
	/* Reset message object */
	CAN_WRITE_CTRL(RECEIVE_STD_OBJ, REC_CODE_EMPTY, 8);
	/* reading the free running timer will unlock any message buffers */
	(void) CANinw(board, timer);
	i = 1; /* signal one received message */
    } else {
	i = 0;
    }

    DBGout();
    return i;
}
Example #7
0
/*
 * Configures bit timing registers directly. Chip must be in bus off state.
 */
int CAN_SetBTR (int board, int btr0, int btr1)
{
    DBGin("CAN_SetBTR");
    DBGprint(DBG_DATA, ("[%d] btr0=%d, btr1=%d", board, btr0, btr1));


    /* ToDO for MCF FlexCAN */

    DBGout();
    return 0;
}
Example #8
0
/* FlexCAN only knows a 'mask' value, code is ignored */
int CAN_SetMask (int board, unsigned int code, unsigned int mask)
{

    DBGin("CAN_SetMask");
    DBGprint(DBG_DATA,("[%d] acc=0x%x mask=0x%x",  board, code, mask));
    CANoutw(board, rxgmskhi, mask >> 16);
    CANoutw(board, rxgmsklo, mask && 16);

    DBGout();
    return 0;
}
Example #9
0
int Can_ConfigRTR( int minor, unsigned message, canmsg_t *Tx )
{
canmsg_t *tmp;

    DBGin("Can_ConfigRTR");
    if( (tmp = kmalloc ( sizeof(canmsg_t), GFP_ATOMIC )) == NULL ){
	    DBGprint(DBG_BRANCH,("memory problem"));
	    DBGout(); return -1;
    }
    Rx_Filter[minor].filter[message].rtr_response = tmp;
    memcpy( Rx_Filter[minor].filter[message].rtr_response , Tx, sizeof(canmsg_t));	
    DBGout(); return 1;
    return 0;
}
Example #10
0
int can_Command(struct inode *inode, struct file *file, Command_par_t * argp)
{
unsigned int minor = iminor(inode);
int cmd;
int rx_fifo = ((struct _instance_data *)(file->private_data))->rx_index;


    cmd =  argp->cmd;

    DBGprint(DBG_DATA,("%s: cmd=%d", __func__, cmd));
    switch (cmd) {
      case CMD_START:
	    CAN_StartChip(minor);
	    break;
      case CMD_STOP:
	    CAN_StopChip(minor);
	    break;
      case CMD_RESET:
	    CAN_ChipReset(minor);
	    break;
      case CMD_CLEARBUFFERS:
	{
	    Can_TxFifoInit(minor);
	    Can_RxFifoInit(minor, rx_fifo);
#if 0
	    if( argp->target = CMD_CLEAR_RX) {
	    } else
	    if( argp->target = CMD_CLEAR_TX) {
	    } else {
		DBGout();
		return(-EINVAL);
	    }
#endif
	}
	    break;
      default:
	    DBGout();
	    return(-EINVAL);
    }
    return 0;
}
int can_Command(struct inode *inode, int cmd)
{
unsigned int minor = MINOR(inode->i_rdev);

    DBGprint(DBG_DATA,("cmd=%d", cmd));
    switch (cmd) {
      case CMD_START:
	    CAN_StartChip(minor);
	    break;
      case CMD_STOP:
	    CAN_StopChip(minor);
	    break;
      case CMD_RESET:
	    CAN_ChipReset(minor);
	    break;
      default:
	    DBGout();
	    return(-EINVAL);
    }
    return 0;
}
/**
*
\brief int ioctl(int fd, int request, ...);
the CAN controllers control interface
\param fd The descriptor to change properties
\param request special configuration request
\param ...  traditional a \a char *argp

The \a ioctl function manipulates the underlying device
parameters of the CAN special device.
In particular, many operating characteristics of
character CAN driver may be controlled with \a ioctl requests.
The argument \a fd must be an open file descriptor.

An ioctl request has encoded in it whether the argument is
an \b in parameter or \b out parameter,
and the size of the argument argp in bytes.
Macros and defines used in specifying an \a ioctl request
are located  in  the  file can4linux.h .

The following \a requests are defined:

\li \c COMMAND some commands for
start, stop and reset the CAN controller chip
\li \c CONFIG configure some of the device properties
like acceptance filtering, bit timings, mode of the output control register
or the optional software message filter configuration(not implemented yet).
\li \c STATUS request the CAN controllers status
\li \c SEND a single message over the \a ioctl interface 
\li \c RECEIVE poll a receive message
\li \c CONFIGURERTR configure automatic rtr responses(not implemented)

The third argument is a parameter structure depending on the request.
These are
\code
struct Command_par
struct Config_par
struct CanSja1000Status_par
struct ConfigureRTR_par
struct Receive_par
struct Send_par
\endcode
described in can4linux.h

\par Acceptance Filtering

\b Basic \b CAN.
In the case of using standard identifiers in Basic CAN mode
for receiving CAN messages
only the low bytes are used to set acceptance code and mask
for bits ID.10 ... ID.3

\par
\b PeliCAN.
For acceptance filtering the entries \c AccCode and \c AccMask are used
like specified in the controllers manual for
\b Single \b Filter \b Configuration .
Both are 4 byte entries.
In the case of using standard identifiers for receiving CAN messages
also all 4 bytes can be used.
In this case two bytes are used for acceptance code and mask
for all 11 identifier bits plus additional the first two data bytes.
The SJA1000 is working in the \b Single \b Filter \ Mode .
\code
       Bits
 mask  31 30 .....           4  3  2  1  0
 code
 -------------------------------------------
 ID    28 27 .....           1  0  R  +--+-> unused
                                   T
                                   R
\endcode

\returns
On success, zero is returned.
On error, -1 is returned, and errno is set appropriately.

\par Example
\code
Config_par_t  cfg;
volatile Command_par_t cmd;


    cmd.cmd = CMD_STOP;
    ioctl(can_fd, COMMAND, &cmd);

    cfg.target = CONF_ACCM; 
    cfg.val    = acc_mask;
    ioctl(can_fd, CONFIG, &cfg);
    cfg.target = CONF_ACCC; 
    cfg.val    = acc_code;
    ioctl(can_fd, CONFIG, &cfg);

    cmd.cmd = CMD_START;
    ioctl(can_fd, COMMAND, &cmd);

\endcode

*/
int can_ioctl( __LDDK_IOCTL_PARAM )
{
void *argp;
int retval = -EIO;
  
  DBGin("can_ioctl");
  DBGprint(DBG_DATA,("cmd=%d", cmd));
  Can_errno = 0;
  
  switch(cmd){

        case COMMAND:
	  if( verify_area(VERIFY_READ, (void *)arg, sizeof(Command_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( verify_area(VERIFY_WRITE, (void *)arg, sizeof(Command_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *) kmalloc( sizeof(Command_par_t) +1 , GFP_KERNEL );
	  __lddk_copy_from_user( (void *) argp,(Command_par_t *) arg,
	  					sizeof(Command_par_t));
	  ((Command_par_t *) argp)->retval =
	  		can_Command(inode, ((Command_par_t *) argp)->cmd );
	  ((Command_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Command_par_t *)arg, (void *)argp,
	  					sizeof(Command_par_t));
	  kfree(argp);
	  break;
      case CONFIG:
	  if( verify_area(VERIFY_READ, (void *) arg, sizeof(Config_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( verify_area(VERIFY_WRITE, (void *) arg, sizeof(Config_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *) kmalloc( sizeof(Config_par_t) +1 ,GFP_KERNEL);
	  __lddk_copy_from_user( (void *) argp,(Config_par_t *) arg,
	  					sizeof(Config_par_t));
	  ((Config_par_t *) argp)->retval =
	  		can_Config(inode, ((Config_par_t *) argp)->target, 
			     ((Config_par_t *) argp)->val1,
			     ((Config_par_t *) argp)->val2 );
	  ((Config_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Config_par_t *) arg, (void *) argp,
	  					sizeof(Config_par_t));
	  kfree(argp);
	  break;
      case SEND:
	  if( verify_area(VERIFY_READ, (void *) arg, sizeof(Send_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( verify_area(VERIFY_WRITE, (void *) arg, sizeof(Send_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(Send_par_t) +1 ,GFP_KERNEL );
	  __lddk_copy_from_user( (void *) argp, (Send_par_t *)arg,
	  				sizeof(Send_par_t));
	  ((Send_par_t *) argp)->retval =
	  		can_Send(inode, ((Send_par_t *) argp)->Tx );
	  ((Send_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Send_par_t *) arg, (void *)argp,
	  				sizeof(Send_par_t));
	  kfree(argp);
	  break;
      case RECEIVE:
	  if( verify_area(VERIFY_READ, (void *) arg, sizeof(Receive_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( verify_area(VERIFY_WRITE, (void *) arg, sizeof(Receive_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(Receive_par_t) +1 ,GFP_KERNEL );
	  __lddk_copy_from_user( (void *)argp, (Receive_par_t *)arg,
	  				sizeof(Receive_par_t));
	  ((Receive_par_t *) argp)->retval =
	  		can_Receive(inode, ((Receive_par_t *) argp)->Rx);
	  ((Receive_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Receive_par_t *)arg, (void *) argp,
	  				sizeof(Receive_par_t));
	  kfree(argp);
	  break;
      case STATUS:
	  if( verify_area(VERIFY_READ, (void *) arg,
	  				sizeof(CanStatusPar_t))) {
	     DBGout(); return(retval); 
	  }
	  if( verify_area(VERIFY_WRITE, (void *) arg,
	  			sizeof(CanStatusPar_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(CanStatusPar_t) +1 ,GFP_KERNEL );
	  ((CanStatusPar_t *) argp)->retval =
	  		can_GetStat(inode, ((CanStatusPar_t *)argp));
	  __lddk_copy_to_user( (CanStatusPar_t *)arg, (void *) argp,
	  				sizeof(CanStatusPar_t));
	  kfree(argp);
	  break;

#ifdef CAN_RTR_CONFIG
      case CONFIGURERTR:
	  if( verify_area(VERIFY_READ, (void *) arg,
	  			sizeof(ConfigureRTR_par_t))){
	     DBGout(); return(retval); 
	  }
	  if( verify_area(VERIFY_WRITE, (void *) arg,
	  			sizeof(ConfigureRTR_par_t))){
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(ConfigureRTR_par_t) +1 ,GFP_KERNEL );
	  __lddk_copy_from_user( (void *) argp,(ConfigureRTR_par_t *) arg,
	  			sizeof(ConfigureRTR_par_t));
	  ((ConfigureRTR_par_t *) argp)->retval =
	  	can_ConfigureRTR(inode,
	  			((ConfigureRTR_par_t *) argp)->message, 
				((ConfigureRTR_par_t *) argp)->Tx );
	  ((ConfigureRTR_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (ConfigureRTR_par_t *) arg, (void *) argp,
	  			sizeof(ConfigureRTR_par_t));
	  kfree(argp);
	  break;

#endif  	/* CAN_RTR_CONFIG */
  
      default:
        DBGout();
	return -EINVAL;
    }
    DBGout();
    return 1;
}
Example #13
0
File: write.c Project: L31N/source
__LDDK_WRITE_TYPE can_write( __LDDK_WRITE_PARAM )
{
unsigned int minor = __LDDK_MINOR;
msg_fifo_t *TxFifo = &Tx_Buf[minor];
canmsg_t *addr;
canmsg_t tx;
unsigned long flags = 0;  /* still needed for local_irq_save() ? */
int written         = 0;
int blocking;
unsigned long _cnt;


    DBGin();
    /* spin_lock_irqsave(&write_splock[minor], flags ); */
#ifdef DEBUG_COUNTER
    Cnt1[minor] = Cnt1[minor] + 1;
#endif /* DEBUG_COUNTER */


    /* detect write mode */
    blocking = !(file->f_flags & O_NONBLOCK);

    DBGprint(DBG_DATA,(" -- write %d msg, blocking=%d", (int)count, blocking));
    /* printk("w[%d/%d]", minor, TxFifo->active); */
    addr = (canmsg_t *)buffer;

    if(!access_ok(VERIFY_READ, (canmsg_t *)addr, count * sizeof(canmsg_t))) {
	written = -EINVAL;
	goto can_write_exit;
    }

    /* enter critical section */
    local_irq_save(flags);

    while( written < count ) {

	if(virtual != 0) {
	/* virtual CAN write, put the frame in all RX queues only */
	int rx_fifo;
	msg_fifo_t   *RxFifo; 
	int16_t myindex = 
		(int16_t)((struct _instance_data *)(file->private_data))->rx_index;
	struct timeval  timestamp;

	DBGprint(DBG_DATA,(" -- write msg %d, virtual, blocking=%d, size=%d",
		    (int)written, blocking, (int)sizeof(canmsg_t)));

	/* depending on the number of open processes
	 * the TX data has to be copied in different
	 * RX FIFOs
	 */

	    /* get one message from the userspace buffer */
	    /* FIXME: with CANFD, does it make sense to copy only the number
	     * of data bytes specified in the length field of canmsg_t ?
	     * Instead of  sizeof(canmsg_t) it is something like
	     * sizeof(canmsg_t) - CAN_MSG_LENGTH  + length 
	     */
	    __lddk_copy_from_user(
		    (canmsg_t *) &tx, 
		    (canmsg_t *) &addr[written],
		    sizeof(canmsg_t) );

	    /* we are taking this as receive time stamp */

	    if (use_timestamp[minor]) {
		do_gettimeofday(&timestamp);
	    } else {
		timestamp.tv_sec  = 0;
		timestamp.tv_usec = 0;
	    }

	for(rx_fifo = 0; rx_fifo < CAN_MAX_OPEN; rx_fifo++) {
	    /* for every rx fifo */
	    if (CanWaitFlag[minor][rx_fifo] == 1) {
		/* this FIFO is in use */
		/* printk(KERN_INFO "self copy to [%d][%d]\n", minor, rx_fifo); */
		    
		/*
		 * Don't copy the message in the receive queue
		 * of the process that sent the message unless
		 * this process requested selfreception.
		 */
		if ((myindex == rx_fifo) && 
		    (selfreception[minor][rx_fifo] == 0))
		{
		    /* printk("CAN[%d][%d] Don't copy message in my queue\n",
		     * minor, rx_fifo); */
		    continue;
		}
		// printk(
		// "CAN[%d][%d] Copy message to queue %d\n",
		 //        minor, myindex, rx_fifo);

		/* prepare buffer to be used */
		RxFifo = &Rx_Buf[minor][rx_fifo];

		RxFifo->data[RxFifo->head].flags = 0;
		memcpy(  
		    (void *)&RxFifo->data[RxFifo->head],
		    (void *)&tx,
		    sizeof(canmsg_t));
		/* Now copy the time stamp to the RX FIFO */
		RxFifo->data[RxFifo->head].timestamp.tv_sec = timestamp.tv_sec;
		RxFifo->data[RxFifo->head].timestamp.tv_usec = timestamp.tv_usec;

		/* Set software overflow flag */
		if((RxFifo->status & BUF_OVERRUN) != 0) {
		    RxFifo->data[RxFifo->head].flags |= MSG_BOVR;
		}

		/* Mark message as 'self sent/received' */
		if ((myindex == rx_fifo) && 
		    (selfreception[minor][rx_fifo] != 0))
		{
		    RxFifo->data[RxFifo->head].flags |= MSG_SELF;
		}
		/* increment write index */
		RxFifo->status = BUF_OK;
		++(RxFifo->head);
		RxFifo->head %= MAX_BUFSIZE;

		if(RxFifo->head == RxFifo->tail) {
		    printk("CAN[%d][%d] RX: FIFO overrun\n", minor, rx_fifo);
		    RxFifo->status = BUF_OVERRUN;
		} 
		/*---------- kick the select() call  -*/
		/* This function will wake up all processes
		   that are waiting on this event queue,
		   that are in interruptible sleep
		*/
		wake_up_interruptible(&CanWait[minor][rx_fifo]); 
	    } /* this FIFO is in use */

	}



	} else {
	    /* we have a real hardware to handle */

	/* Do we really need to protect something here ????
	 * e.g. in this case the TxFifo->free[TxFifo->head] value
	 *
	 * If YES, we have to use spinlocks for synchronization
	 */

/* - new Blocking code -- */

	if(blocking) {
	    if(wait_event_interruptible(CanOutWait[minor], \
		    TxFifo->free[TxFifo->head] != BUF_FULL)) {
		written = -ERESTARTSYS;
		goto can_write_exit;
	    }
	} else {
	    /* there are data to write to the network */
	    if(TxFifo->free[TxFifo->head] == BUF_FULL) {
		/* but there is already one message at this place */;
		/* write buffer full in non-blocking mode, leave write() */
		goto can_write_exit;
	    }
	}

/* ---- */

	/*
	 * To know which process sent the message we need an index.
	 * This is used in the TX IRQ to decide in which receive queue
	 * this message has to be copied (selfreception)
	 */
	addr[written].cob = 
		(int16_t)((struct _instance_data *)(file->private_data))->rx_index;
	if( TxFifo->active ) {
	    /* more than one data and actual data in queue,
	     * add this message to the Tx queue 
	     */
	    __lddk_copy_from_user(	/* copy one message to FIFO */
		    (canmsg_t *) &(TxFifo->data[TxFifo->head]), 
		    (canmsg_t *) &addr[written],
		    sizeof(canmsg_t) );
	    TxFifo->free[TxFifo->head] = BUF_FULL; /* now this entry is FULL */
	    /* TxFifo->head = ++(TxFifo->head) % MAX_BUFSIZE; */
	    ++TxFifo->head;
	    (TxFifo->head) %= MAX_BUFSIZE;

	} else {
	    /* copy message into local canmsg_t structure */
	    __lddk_copy_from_user(
		    (canmsg_t *) &tx, 
		    (canmsg_t *) &addr[written],
		    sizeof(canmsg_t) );
	    /* f - fast -- use interrupts */
	    if( count >= 1 ) {
	        /* !!! CHIP abh. !!! */
	        TxFifo->active = 1;
	    }
	    /* write CAN msg data to the chip and enable the tx interrupt */
	    CAN_SendMessage( minor, &tx);  /* Send, no wait */
	}	/* TxFifo->active */
    }
        written++;
    }
Example #14
0
__LDDK_WRITE_TYPE can_write( __LDDK_WRITE_PARAM )
{
unsigned int minor = __LDDK_MINOR;
msg_fifo_t *TxFifo = &Tx_Buf[minor];
canmsg_t *addr;
canmsg_t tx;
unsigned long flags;
int written        = 0;

    DBGin("can_write");
#ifdef DEBUG_COUNTER
    Cnt1[minor] = Cnt1[minor] + 1;
#endif /* DEBUG_COUNTER */

/* DEBUG_TTY(1, "write: %d", count); */
    DBGprint(DBG_DATA,(" -- write %d msg\n", count));
    /* printk("w[%d/%d]", minor, TxFifo->active); */
    addr = (canmsg_t *)buffer;

    if(verify_area(VERIFY_READ, (canmsg_t *)addr, count * sizeof(canmsg_t))) { 
      DBGout();return -EINVAL;
    }
    while( written < count ) {
	/* enter critical section */
	save_flags(flags);cli();
	/* there are data to write to the network */
	if(TxFifo->free[TxFifo->head] == BUF_FULL) {
/* DEBUG_TTY(1, "ret buffer full"); */
	    /* there is already one message at this place */;
	    DBGout();
	    /* return -ENOSPC; */
            return written;
	}
	if( TxFifo->active ) {
	    /* more than one data and actual data in queue */
	    __lddk_copy_from_user(	/* copy one message to FIFO */
		    (canmsg_t *) &(TxFifo->data[TxFifo->head]), 
		    (canmsg_t *) &addr[written],
		    sizeof(canmsg_t) );
/* DEBUG_TTY(1, " fifo active: id %d/%x; head %d/tail %d", */
/* TxFifo->data[TxFifo->head].id, */
/* TxFifo->data[TxFifo->head].id, */
/* TxFifo->head, */
/* TxFifo->tail); */
	    TxFifo->free[TxFifo->head] = BUF_FULL; /* now this entry is FULL */
	    TxFifo->head = ++(TxFifo->head) % MAX_BUFSIZE;
        } else {
	    __lddk_copy_from_user(
		    (canmsg_t *) &tx, 
		    (canmsg_t *) &addr[written],
		    sizeof(canmsg_t) );
/* DEBUG_TTY(1, " fifo in-active: id %d/%x; head %d/tail %d", */
		/* tx.id, tx.id, */
/* TxFifo->head, */
/* TxFifo->tail ); */
	  /* f - fast -- use interrupts */


            //  Hack hobe TxFifo->active = 0; wird normalerweise auf 1 gesetzt --> und wenn der Inaterrupt
            //  kommt dann wird in Can_Interrupt TxFifo->active wieder zurĆ¼ckgesetzt!!!

            if( count >= 1 ) {
	    /* !!! CHIP abh. !!! */
	    TxFifo->active = 1;
	  }
	  CAN_SendMessage( minor, &tx);  /* Send, no wait */
	}
        written++;
	/* leave critical section */
	restore_flags(flags);
    }
    /* printk("W[%d/%d]", minor, TxFifo->active); */
    DBGout();
    return written;
}
Example #15
0
enum PubNub_BH PubNub::_request_bh(PubNub_BASE_CLIENT &client, unsigned long t_start, int timeout)
{
	/* Finish the first line of the request. */
	client.print(" HTTP/1.1\r\n");
	/* Finish HTTP request. */
	client.print("Host: ");
	client.print(origin);
	client.print("\r\nUser-Agent: PubNub-Arduino/1.0\r\nConnection: close\r\n\r\n");

#define WAIT() do { \
	while (!client.available()) { \
		/* wait, just check for timeout */ \
		if (millis() - t_start > (unsigned long) timeout * 1000) { \
			DBGprintln("Timeout in bottom half"); \
			return PubNub_BH_TIMEOUT; \
		} \
		if (!client.connected()) { \
			/* Oops, connection interrupted. */ \
			DBGprintln("Connection reset in bottom half"); \
			return PubNub_BH_ERROR; \
		} \
	} \
} while (0)

	/* Read first line with HTTP code. */
	/* "HTTP/1.x " */
	do {
		WAIT();
	} while (client.read() != ' ');
	/* Now, first digit of HTTP code. */
	WAIT();
	char c = client.read();
	if (c != '2') {
		/* HTTP code that is NOT 2xx means trouble.
		 * kthxbai */
		DBGprint("Wrong HTTP status first digit ");
		DBGprint((int) c, DEC);
		DBGprintln(" in bottom half");
		return PubNub_BH_ERROR;
	}

	/* Now, we enter in a state machine that shall guide us through
	 * the remaining headers to the beginning of the body. */
	enum {
		RS_SKIPLINE, /* Skip the rest of this line. */
		RS_LOADLINE, /* Try loading the line in a buffer. */
	} request_state = RS_SKIPLINE; /* Skip the rest of status line first. */
	bool chunked = false;

	while (client.connected() || client.available()) {
		/* Let's hope there is no stray LF without CR. */
		if (request_state == RS_SKIPLINE) {
			do {
				WAIT();
			} while (client.read() != '\n');
			request_state = RS_LOADLINE;

		} else { /* request_state == RS_LOADLINE */
			/* line[] must be enough to hold
			 * Transfer-Encoding: chunked (or \r\n) */
			const static char PROGMEM chunked_str[] = "Transfer-Encoding: chunked\r\n";
			char line[sizeof(chunked_str)]; /* Not NUL-terminated! */
			int linelen = 0;
			char ch = 0;
			do {
				WAIT();
				ch = client.read();
				line[linelen++] = ch;
				if (linelen == strlen_P(chunked_str)
				    && !strncasecmp_P(line, chunked_str, linelen)) {
					/* Chunked encoding header. */
					chunked = true;
					break;
				}
			} while (ch != '\n' && linelen < sizeof(line));
			if (ch != '\n') {
				/* We are not at the end of the line yet.
				 * Skip the rest of the line. */
				request_state = RS_SKIPLINE;
			} else if (linelen == 2 && line[0] == '\r') {
				/* Empty line. This means headers end. */
				break;
			}
		}
	}

	if (chunked) {
		/* There is one extra line due to Transfer-encoding: chunked.
		 * Our minimalistic support means that we hope for just
		 * a single chunk, just skip the first line after header. */
		do {
			WAIT();
		} while (client.read() != '\n');
	}

	/* Body begins now. */
	return PubNub_BH_OK;
}
Example #16
0
int CAN_SendMessage (int board, canmsg_t *tx)
{
int i = 0;
volatile u16 stat;

    DBGin("CAN_SendMessage");

    /*
    IDLE - Idle Status. The IDLE bit indicates, when there is activity
    on the CAN bus
    1 - The CAN bus is Idle

    TX/RX - Transmission/receive status.
    Indicates when the FlexCAN module is transmitting or receiving a message.
    TX/RX has no meaning, when IDLE = 1
	0 - FlexCAN is receiving when IDLE = 0
	1 - FlexCAN is transmitting when IDLE = 0
    */

    while (
    	    ((stat = CANinw(board, estat)) & (CAN_ESTAT_IDLE + CAN_ESTAT_TX_RX))
    	    == CAN_ESTAT_TX_RX
    	  ) {

	if (current->need_resched) schedule();
	/* if( need_resched ) schedule(); */

    }

    /* DBGprint(DBG_DATA,( */
    		/* "CAN[%d]: tx.flags=%d tx.id=0x%lx tx.length=%d stat=0x%x", */
		/* board, tx->flags, tx->id, tx->length, stat)); */

    tx->length %= 9;			/* limit CAN message length to 8 */


    /* Writing Control/Status word to hold TX Message Object inactive */
    CAN_WRITE_CTRL(TRANSMIT_OBJ, TRANS_CODE_NOT_READY, 1);

    /* fill the frame info and identifier fields , ID-Low and ID-High */
    if(tx->flags & MSG_EXT) {
    	/* use ID in extended message format */
	DBGprint(DBG_DATA, ("---> send ext message \n"));
	if( tx->flags & MSG_RTR) {
	    CAN_WRITE_XOID_RTR(TRANSMIT_OBJ, tx->id);
	} else {
	    CAN_WRITE_XOID(TRANSMIT_OBJ, tx->id);
	}
    } else {
	DBGprint(DBG_DATA, ("---> send std message \n"));
	if( tx->flags & MSG_RTR) {
	    CAN_WRITE_OID_RTR(TRANSMIT_OBJ, tx->id);
	} else {
	    CAN_WRITE_OID(TRANSMIT_OBJ, tx->id);
	}
    }

    /* - fill data ---------------------------------------------------- */

    for(i = 0; i < tx->length; i++) {
    	CAN_OBJ[TRANSMIT_OBJ].msg[i] = tx->data[i];
    }
    /* Writing Control/Status word (active code, length) */
    CAN_WRITE_CTRL(TRANSMIT_OBJ, TRANS_CODE_TRANSMIT_ONCE, tx->length);

    /* - /end --------------------------------------------------------- */
    DBGout();return i;
}
Example #17
0
int can_select( __LDDK_SELECT_PARAM )
#endif
{

unsigned int minor = __LDDK_MINOR;
msg_fifo_t *RxFifo = &Rx_Buf[minor];
    DBGin("can_select");
	    DBGprint(DBG_DATA,("minor = %d", minor));
#if 0
	    DBGprint(DBG_DATA,("file = %p", file));
	    ;
	    DBGprint(DBG_DATA,("s(CanWait[]) = %2d", sizeof(CanWait[0])));
	    ;
	    /* DBGprint(DBG_DATA,("s(CanWait)   = %2d", sizeof(CanWait))); */
	    ;
	    DBGprint(DBG_DATA,("&CanWait[] = %p", &CanWait[0]));
	    DBGprint(DBG_DATA,("CanWait[minor].task_list.n = %p", CanWait[minor].task_list.next));
	    DBGprint(DBG_DATA,("CanWait[minor].task_list.p = %p", CanWait[minor].task_list.prev));
	    DBGprint(DBG_DATA,("&CanWait[minor]->task_list.p = %p", (&CanWait[minor])->task_list.prev));

	    DBGprint(DBG_DATA,("wait = %p", wait));
	    if(wait) {
	    DBGprint(DBG_DATA,("wait->error = %d", wait->error));
	    DBGprint(DBG_DATA,("wait->table = %p", wait->table));
	    } else {
	    DBGprint(DBG_DATA,("can not dereference wait components"));
	    }
#endif
#ifdef DEBUG
    CAN_ShowStat(minor);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
    DBGprint(DBG_BRANCH,("POLL: fifo empty,poll waiting...\n"));

    /* every event queue that could wake up the process
     * and change the status of the poll operation
     * can be added to the poll_table structure by
     * calling the function poll_wait:  
     */
                /*     _select para, wait queue, _select para */
/* X */		poll_wait(file, &CanWait[minor] , wait);

    DBGprint(DBG_BRANCH,("POLL: wait returned \n"));
    if( RxFifo->head != RxFifo->tail ) {
	/* fifo has some telegrams */
	/* Return a bit mask
	 * describing operations that could be immediately performed
	 * without blocking.
	 */
	DBGout();
	/*
	 * POLLIN This bit must be set
	 *        if the device can be read without blocking. 
	 * POLLRDNORM This bit must be set
	 * if "normal'' data is available for reading.
	 * A readable device returns (POLLIN | POLLRDNORM)
	 *
	 *
	 *
	 */
	return POLLIN | POLLRDNORM;
    }
    DBGout();return 0;

#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,3)
    DBGprint(DBG_BRANCH,("POLL: fifo empty,poll waiting...\n"));
    poll_wait(file, &CanWait[minor] , wait);
    DBGprint(DBG_BRANCH,("POLL: wait returned \n"));
    if( RxFifo->head != RxFifo->tail ) {
	/* fifo has some telegrams */
	DBGout();
	return POLLIN | POLLRDNORM;
    }
    DBGout();return 0;

#else
    switch (sel_type) {
	case SEL_IN:
	    DBGprint(DBG_BRANCH,("sel_in \n"));
	    if( RxFifo->head == RxFifo->tail ) {
		DBGprint(DBG_BRANCH,("fifo empty \n"));
		select_wait(&CanWait[minor],wait);
		DBGout();return 0;
	    }
	    break;
	case SEL_OUT:
	    DBGprint(DBG_BRANCH,("sel_out \n"));
	    /* ready for write ? */
	    select_wait(&CanWait[minor],wait);
	    DBGout();return 0;
    }
    DBGout();return 1;
#endif

        
    DBGout();
    return 0;
}
Example #18
0
irqreturn_t CAN_Interrupt ( int irq, void *dev_id, struct pt_regs *ptregs )
{
volatile unsigned int		estat;
volatile unsigned int		ctrl;
volatile unsigned int 		irqsrc;
static int erroractive = 1;
int		dummy;
unsigned long	flags;
int		board;
msg_fifo_t	*RxFifo;
msg_fifo_t	*TxFifo;
int 		i;
static int	last_tx_id;	/* should be global, -1, set bei transmit  */
				/* and should be an array for each channel */

int full = 0;

    set_led();

    board = *(int *)dev_id;

    RxFifo = &Rx_Buf[board];
    TxFifo = &Tx_Buf[board];

    /* DBGprint(DBG_DATA, (" => got  IRQ[%d]: 0x%0x\n", board, irqsrc)); */


    /* One of the following can actually occur:
    IntNr Reason
     153   BusOff				
     152   ErrInt - in this case:
	    bits 4-5 - ESTAT.FCS - Fault Confinment State tells us
	     00 - all ok, error active mode
	     01 - error passive mode
	    bit 8 - RX warning level reached
	    bit 9 - Tx warning level reached
     154   WakeUp Interrupt

       At the moment we aren't interested in more information

       all bits in estat are read only except for
       BOFF_INT WAKE_INT und ERR_INT which are interrupt sources
       and can be written by the host to '0' to reset Interrupt
       conditions.
    */
    estat = CANinw(board, estat);
    if( estat
        & (CAN_ESTAT_BOFF_INT | CAN_ESTAT_ERR_INT | CAN_ESTAT_WAKE_INT))  {
	CANoutw(board, estat, 0);
	CANoutw(board, estat, 0);
	CANoutw(board, estat, 0xffff);
    }

    /* error interrupts are :
       if (irq == 152 || irq == 153 || irq == 154)
       we could test the irq or read out the estat register
     */
/* printk("1"); */
    if (estat &
       (CAN_ESTAT_BOFF_INT | CAN_ESTAT_ERR_INT | CAN_ESTAT_WAKE_INT))  {
	/* we have an error interrupt
	 * later on we can move this error handling at the end of the ISR
	 * to have better RX response times */
            /* 1111 */
	/* printk(" error-1 status 0x%04x \n", estat); */
	/* printk(" 0x%04x\n", estat); */
	/* reset all error conditions, we have saved them in estat
	 * BusOff disables the Interrupt generation itself by resetting
	 * the mask in canctrl0.
	 * ErrInt - to clear this bit, first read it (already done)
	 * then write as a zero.
	 *
	 * we do reset all possible interrupts and look what we got later
	 */
/* printk("2"); */
	CANresetw(board, estat,
	    (CAN_ESTAT_BOFF_INT + CAN_ESTAT_ERR_INT + CAN_ESTAT_WAKE_INT));
	CANoutw(board, estat, 0xffff);

	/* Getting a precises time takes a lot of time
	 * if a time stamp is not needed, it can be switched of
	 * by ioctl() */
	if(timestamp[board]) {
	    do_gettimeofday(&(RxFifo->data[RxFifo->head]).timestamp);
	} else {
	    (RxFifo->data[RxFifo->head]).timestamp.tv_sec  = 0;
	    (RxFifo->data[RxFifo->head]).timestamp.tv_usec  = 0;
	}
	/* check for Bus Off condition */
	if (estat & CAN_ESTAT_BOFF_INT) {
	    /* printk("BusOff\n"); */

	    (RxFifo->data[RxFifo->head]).id = 0xFFFFFFFF;
	    (RxFifo->data[RxFifo->head]).flags = MSG_BUSOFF; 
	    RxFifo->status = BUF_OK;
	    RxFifo->head = ++(RxFifo->head) % MAX_BUFSIZE;
	    if(RxFifo->head == RxFifo->tail) {
		    printk("CAN[%d] RX: FIFO overrun\n", board);
		    RxFifo->status = BUF_OVERRUN;
	    } 
	    /* tell someone that there is a new error message */
	    wake_up_interruptible(&CanWait[board]); 

	}
	if (CAN_ESTAT_TX_WARN ==
			(estat & (CAN_ESTAT_ERR_INT + CAN_ESTAT_TX_WARN))) {
	    /* printk("Tx Warning level reached\n"); */
	}
	if (CAN_ESTAT_RX_WARN ==
			(estat & (CAN_ESTAT_ERR_INT + CAN_ESTAT_RX_WARN))) {
	    /* printk("Rx Warning level reached\n"); */
	}
	/* FCS - the Fault Confinement State 
	 *   if CAN_ESTAT_FCS0 is set :  Error Passive
	 *   else Error Active   
	 */
	/* if (estat & (CAN_ESTAT_ERR_INT + CAN_ESTAT_FCS)) { */


	/* Going back to Error Active can happen without an error Int ? */
	    if(0 == (estat & CAN_ESTAT_FCS)) {
		if (!erroractive) {
		    /* printk("Going error active\n"); */
		    /* do what you like here */
	        }
	        erroractive = 1;
	    }
	    if(CAN_ESTAT_FCS0 == (estat & CAN_ESTAT_FCS)) {
		if (erroractive) {
		    /* printk("Going error passive\n"); */
		    (RxFifo->data[RxFifo->head]).id = 0xFFFFFFFF;
		    (RxFifo->data[RxFifo->head]).flags = MSG_PASSIVE; 
		    RxFifo->status = BUF_OK;
		    RxFifo->head = ++(RxFifo->head) % MAX_BUFSIZE;
		    if(RxFifo->head == RxFifo->tail) {
			    printk("CAN[%d] RX: FIFO overrun\n", board);
			    RxFifo->status = BUF_OVERRUN;
		    } 
		    wake_up_interruptible(&CanWait[board]); 
		}
	        erroractive = 0;
	    }
	/* } */
	CANresetw(board, estat,
	    (CAN_ESTAT_BOFF_INT + CAN_ESTAT_ERR_INT + CAN_ESTAT_WAKE_INT));
    }

    if(0 == (estat & CAN_ESTAT_FCS)) {
	if (!erroractive) {
	    /* printk("Going error active\n"); */
	    /* do what you like here */
	}
	erroractive = 1;
    }


    /*
     loop as long as the CAN controller shows interrupts.
     check for message object interrupts.
    */
    while(1) {
	irqsrc = CANinw(board, iflag);
	/* printk("   0x%0x\n", irqsrc); */
	if (irqsrc == 0) break;

	/*
	 * If there is any IRQ, reset all of them, the IRQ sources are stored
	 * in the irqsrc variable for later evaluation.
	 * 5282 overwrites/clears with '1'
	 */
	CANoutw(board, iflag, irqsrc /* 0xffff */);

	if(timestamp[board]) {
	    do_gettimeofday(&(RxFifo->data[RxFifo->head]).timestamp);
	} else {
	    (RxFifo->data[RxFifo->head]).timestamp.tv_sec  = 0;
	    (RxFifo->data[RxFifo->head]).timestamp.tv_usec  = 0;
	}

	/* preset flags */
	(RxFifo->data[RxFifo->head]).flags =
			    (RxFifo->status & BUF_OVERRUN ? MSG_BOVR : 0);

	/* CANresetw(board, estat,  */
	   /* (CAN_ESTAT_BOFF_INT + CAN_ESTAT_ERR_INT + CAN_ESTAT_WAKE_INT)); */


    /*========== receive interrupt */
    if( irqsrc & ((1 << RECEIVE_STD_OBJ) + (1 << RECEIVE_EXT_OBJ))) {

	unsigned oid;
	int mrobject;	/* number of the message receive object */

	DBGprint(DBG_DATA, (" => got  RX IRQ[%d]: 0x%0x\n", board, irqsrc));

        /* Handle differences between base format frames and extended frames */
        if (irqsrc & (1 << RECEIVE_STD_OBJ)) {
            mrobject = RECEIVE_STD_OBJ;
	    while (((ctrl = CAN_READ_CTRL(RECEIVE_STD_OBJ))
			   & (REC_CODE_BUSY << 4)) == (REC_CODE_BUSY << 4)) {
		/* 20 cycles maximum wait */
		/* printf1("CAN_int, rx REC_CODE_BUSY"); */
	    }
	    last_tx_id = CAN_READ_OID(TRANSMIT_OBJ);
	    oid        = CAN_READ_OID(RECEIVE_STD_OBJ);
	} else {
            mrobject = RECEIVE_EXT_OBJ;
	    while (((ctrl = CAN_READ_CTRL(RECEIVE_EXT_OBJ))
			   & (REC_CODE_BUSY << 4)) == (REC_CODE_BUSY << 4)) {
		/* 20 cycles maximum wait */
		/* printf1("CAN_int, rx REC_CODE_BUSY"); */
	    }
	    last_tx_id = CAN_READ_XOID(TRANSMIT_OBJ);
	    oid        = CAN_READ_XOID(RECEIVE_EXT_OBJ);

	}
	/* printk(" %d/%x == %d/%x\n", oid, oid, last_tx_id, last_tx_id); */
	if (oid == last_tx_id) {
            /*
	    This is obviously a message we sent ourselves recently.
            The FlexCAN receives self-transmitted frames
            if there exists a matching receive MB.
	    There is no point in delivering this to the upper layer.
	    At least for using the driver in standard applications.
	    A CAN Analyser using can4linux _is_ interested in a time stamp
	    for the sent frame too.
	    We rely on the fact
	    that no other node will ever send a message with the same OID.
            */
	    if (selfreception[board]) {
		(RxFifo->data[RxFifo->head]).flags |= MSG_SELF;
	    } else {
		goto ResetRXInt;
	    }
	}

	(RxFifo->data[RxFifo->head]).id =  oid;
	if(mrobject ==  RECEIVE_STD_OBJ) {
	    /* (RxFifo->data[RxFifo->head]).id =  CAN_READ_OID(mrobject); */
	} else {
	    /* (RxFifo->data[RxFifo->head]).id =  CAN_READ_XOID(mrobject); */
	    (RxFifo->data[RxFifo->head]).flags |= MSG_EXT;
	}
	/* printk("CAN[%d] received id %d\n", */
		    /* board, (RxFifo->data[RxFifo->head]).id); */

	/* get message length,  strip length code */
	dummy = ctrl & 0x0f;
	(RxFifo->data[RxFifo->head]).length = dummy;
	dummy %= 9;	/* limit count to 8 bytes */

#if 0
/* There was reported a problem with using memcpy resulting in corrupted data */
	memcpy(&(RxFifo->data[RxFifo->head]).data[0],\
	    &(CAN_OBJ[RECEIVE_STD_OBJ].MSG0), dummy);
#else


#if 1
	for( i = 0; i < dummy; i++) {
	    RxFifo->data[RxFifo->head].data[i] =
			    CAN_OBJ[mrobject].msg[i];
	}
#else
	(RxFifo->data[RxFifo->head]).length = 8;

	RxFifo->data[RxFifo->head].data[0] =  RxFifo->head;
	RxFifo->data[RxFifo->head].data[1] =  RxFifo->tail;

#endif
#endif

	/* mark just written entry as OK and full */
	RxFifo->status = BUF_OK;

        /* adjust write pointer for received messages */
        if (!full) {
        RxFifo->head = (++(RxFifo->head)) % MAX_BUFSIZE;
        }

        if (RxFifo->head > RxFifo->tail)  printk("+");
        if (RxFifo->head < RxFifo->tail)  printk("-");

        if(RxFifo->head == RxFifo->tail) {
	    /* This was the last message which is fitting in the RX buffer */
	    /* printk("CAN[%d] RX: FIFO overrun\n", board); */
	    RxFifo->status = BUF_OVERRUN;
	    printk("CAN RX: FIFO overrun %d/%d\n", RxFifo->head, RxFifo->tail );
	    full = 1;
        } else full = 0;

	/*---------- kick the select() call  -*/
	/* This function will wake up all processes
	   that are waiting on this event queue,
	   that are in interruptible sleep
	*/
	wake_up_interruptible(&CanWait[board]);


	/* check for CAN controller overrun */
	/* ToDo */
ResetRXInt:
	CAN_WRITE_CTRL(mrobject, REC_CODE_EMPTY, 8);
	/* reading the free running timer will unlock any message buffers */
	(void) CANinw(board, timer);

    }
    /*========== transmit interrupt */
    if( irqsrc & (1 << TRANSMIT_OBJ)) {
	DBGprint(DBG_DATA, (" => got  TX IRQ[%d]: 0x%0x\n", board, irqsrc));
	/* CAN_register_dump(); */
	if( TxFifo->free[TxFifo->tail] == BUF_EMPTY ) {
	    /* TX FIFO empty, nothing more to sent */
	    /* printk("TXE\n"); */
	    TxFifo->status = BUF_EMPTY;
            TxFifo->active = 0;
	    /* This function will wake up all processes
	       that are waiting on this event queue,
	       that are in interruptible sleep
	    */
	    wake_up_interruptible(&CanOutWait[board]); 
            goto Tx_done;
	} else {
	    /* printk("TX\n"); */
	}

        /* enter critical section */
        save_flags(flags);cli();

        while ((ctrl = CAN_READ_CTRL(TRANSMIT_OBJ)
                 & (REC_CODE_BUSY << 4)) == (REC_CODE_BUSY << 4)) {
        	/* printk("CAN_int, tx REC_CODE_BUSY"); */
	}

	/* now we can check here if an RTR was received with this TX channel */
	if ((    CAN_READ_CTRL(TRANSMIT_OBJ)
	      & (REC_CODE_FULL << 4)) == (REC_CODE_FULL << 4))
	{
            printk("CAN_int, got rx interrupt on transmit channel,  OID= %d\n",
						    CAN_READ_OID(TRANSMIT_OBJ));
	} else {
	    /* Real Transmit Interrupt */

	    /* Writing Control/Status word to hold TX Message Object inactive */
	    CAN_WRITE_CTRL(TRANSMIT_OBJ, TRANS_CODE_NOT_READY, 1);

	    /* fill the frame info and identifier fields , ID-Low and ID-High */
	    if( (TxFifo->data[TxFifo->tail]).flags & MSG_EXT ) {
		/* use ID in extended message format */
		DBGprint(DBG_DATA, ("---> send ext message \n"));
		if( (TxFifo->data[TxFifo->tail]).flags & MSG_RTR) {
		    CAN_WRITE_XOID_RTR(TRANSMIT_OBJ,
		    	(TxFifo->data[TxFifo->tail]).id);
		} else {
		    CAN_WRITE_XOID(TRANSMIT_OBJ,
		    	(TxFifo->data[TxFifo->tail]).id);
		}
	    } else {
		DBGprint(DBG_DATA, ("---> send std message \n"));
		if( (TxFifo->data[TxFifo->tail]).flags & MSG_RTR) {
		    CAN_WRITE_OID_RTR(TRANSMIT_OBJ,
		    	(TxFifo->data[TxFifo->tail]).id);
		} else {
		    CAN_WRITE_OID(TRANSMIT_OBJ,
		    	(TxFifo->data[TxFifo->tail]).id);
		}
	    }

#if 0
/* There was reported a problem with using memcpy resulting in corrupted data */
	    memcpy( (void *)&(CAN_OBJ[TRANSMIT_OBJ].MSG0),
		(const void *)&(TxFifo->data[TxFifo->tail]).data[0],
		(TxFifo->data[TxFifo->tail]).length);
#else
	    for( i = 0; i < (TxFifo->data[TxFifo->tail]).length; i++) {
		    CAN_OBJ[TRANSMIT_OBJ].msg[i] =
			TxFifo->data[TxFifo->tail].data[i];
	    }

#endif


	    /* Writing Control/Status word (active code, length) */
	    CAN_WRITE_CTRL(TRANSMIT_OBJ, TRANS_CODE_TRANSMIT_ONCE,
		    (TxFifo->data[TxFifo->tail]).length);

	    TxFifo->free[TxFifo->tail] = BUF_EMPTY; /* now this entry is EMPTY */
	    TxFifo->tail = ++(TxFifo->tail) % MAX_BUFSIZE;

	    /* leave critical section */
	    restore_flags(flags);
	}

Tx_done:
	/* Reset Interrupt pending at Transmit Object */
	/* CANsetw(board, iflag, ~(1 << TRANSMIT_OBJ)); */
	/* CANsetw(board, iflag, (1 << TRANSMIT_OBJ)); */
   }
	/* for some reason it wasn't good enough to reset iflag
	 * just after reading the iflag register in while( (irqsrc = ...)
	 */
	/* CANsetw(board, iflag, ~(1 << TRANSMIT_OBJ)); */
   }
Example #19
0
int can_ioctl( __LDDK_IOCTL_PARAM )
#endif 
{
void *argp;
int retval = -EIO;
unsigned long _cnt;
int ret;
#if defined(DEBUG) 
unsigned int minor = __LDDK_MINOR;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) 
  struct inode *inode = file->f_path.dentry->d_inode;
#endif   
  DBGin();
  DBGprint(DBG_DATA,("cmd=%d", cmd));
  Can_errno = 0;

  switch(cmd){

        case CAN_IOCTL_COMMAND:
	  if( !access_ok(VERIFY_READ, (void *)arg, sizeof(Command_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( !access_ok(VERIFY_WRITE, (void *)arg, sizeof(Command_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *) kmalloc( sizeof(Command_par_t) +1 , GFP_KERNEL );
	  __lddk_copy_from_user( (void *)argp, (Command_par_t *)arg,
	  					sizeof(Command_par_t));
	  ((Command_par_t *) argp)->retval =
	  		can_Command(inode, file, (Command_par_t *)argp);
	  ((Command_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Command_par_t *)arg, (void *)argp,
	  					sizeof(Command_par_t));
	  kfree(argp);
	  ret = 0;
	  break;
      case CAN_IOCTL_CONFIG:
	  if( !access_ok(VERIFY_READ, (void *)arg, sizeof(Config_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( !access_ok(VERIFY_WRITE, (void *)arg, sizeof(Config_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *) kmalloc( sizeof(Config_par_t) +1 ,GFP_KERNEL);
	  __lddk_copy_from_user( (void *)argp, (Config_par_t *)arg,
	  					sizeof(Config_par_t));
	  retval = can_Config(inode, file, ((Config_par_t *)argp)->target, 
			     ((Config_par_t *)argp)->val1,
			     ((Config_par_t *)argp)->val2 );
	  ((Config_par_t *) argp)->retval = retval;
	  ((Config_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Config_par_t *)arg, (void *)argp,
	  					sizeof(Config_par_t));
	  kfree(argp);
	  if (0 != retval) {
	    ret = -EINVAL;
	  } else {
	      ret = 0;
	  }
	  break;
      case CAN_IOCTL_SEND:
	  if( !access_ok(VERIFY_READ, (void *)arg, sizeof(Send_par_t))) {
	     DBGout(); return(retval); 
	  }
	  if( !access_ok(VERIFY_WRITE, (void *)arg, sizeof(Send_par_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(Send_par_t) +1 ,GFP_KERNEL );
	  __lddk_copy_from_user( (void *)argp, (Send_par_t *)arg,
	  				sizeof(Send_par_t));
	  ((Send_par_t *) argp)->retval =
	  		can_Send(inode, ((Send_par_t *)argp)->Tx );
	  ((Send_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (Send_par_t *)arg, (void *)argp,
	  				sizeof(Send_par_t));
	  kfree(argp);
	  ret = 0;
	  break;
      case CAN_IOCTL_STATUS:
	  if( !access_ok(VERIFY_READ, (void *)arg,
	  				sizeof(CanStatusPar_t))) {
	     DBGout(); return(retval); 
	  }
	  if( !access_ok(VERIFY_WRITE, (void *)arg,
	  			sizeof(CanStatusPar_t))) {
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(CanStatusPar_t) +1 ,GFP_KERNEL );
	  ((CanStatusPar_t *) argp)->retval =
	  		can_GetStat(inode, file, ((CanStatusPar_t *)argp));
	  __lddk_copy_to_user( (CanStatusPar_t *)arg, (void *)argp,
	  				sizeof(CanStatusPar_t));
	  kfree(argp);
	  ret  = 0;
	  break;

#ifdef CAN_RTR_CONFIG
      case CAN_IOCTL_CONFIGURERTR:
	  if( !access_ok(VERIFY_READ, (void *)arg,
	  			sizeof(ConfigureRTR_par_t))){
	     DBGout(); return(retval); 
	  }
	  if( !access_ok(VERIFY_WRITE, (void *)arg,
	  			sizeof(ConfigureRTR_par_t))){
	     DBGout(); return(retval); 
	  }
	  argp = (void *)kmalloc( sizeof(ConfigureRTR_par_t) +1 ,GFP_KERNEL );
	  __lddk_copy_from_user( (void *)argp, (ConfigureRTR_par_t *) arg,
	  			sizeof(ConfigureRTR_par_t));
	  ((ConfigureRTR_par_t *) argp)->retval =
	  	can_ConfigureRTR(inode,
	  			((ConfigureRTR_par_t *)argp)->message, 
				((ConfigureRTR_par_t *)argp)->Tx );
	  ((ConfigureRTR_par_t *) argp)->error = Can_errno;
	  __lddk_copy_to_user( (ConfigureRTR_par_t *)arg, (void *)argp,
	  			sizeof(ConfigureRTR_par_t));
	  kfree(argp);
	  ret = 0;
	  break;

#endif  	/* CAN_RTR_CONFIG */
  
      default:
        DBGout();
	ret = -EINVAL;
    }
    DBGout();
    return ret;
}
Example #20
0
/*
 * PCM3680  Remarks
 *
 * Adresses used related to the Basde adress (set by dip switches) 
 * Base address (hex)      CAN controller
 * base:0000h - base:00FFh Basic- Port 1
 * base:0100h - base:01FFh HW reset Basic - Port 1
 * base:0200h - base:02FFh Basic- Port 2
 * base:0300h - base:03FFh HW reset Basic - Port 2
 * base:0400h - base:0FFFh Not used
 * 
 * Each CAN channel uses 0x200 bytes
 */
int CAN_VendorInit (int minor)
{
    DBGin("CAN_VendorInit");

    /* both, the CPC-104 and the PCM3680 */
    can_range[minor] = 0x200;
    

    /* Some LINUX systems, e.g. the PIP10 I tested on,
     * locate already the memory using the information
     * provided in the "Option ROM"
     * The memory is marked as "Adapter-ROM" in /proc/iomem.
     * In this case the drive should not try to allocate the IO mem */

    if(Base[minor] < 0xD8000) {
	/* By definition a EMS CPC-104 */

printk(" can%d is an CPC-104, don't need to allocate iomem\n", minor);
	;

    } else {
	/* By definition a Advantech PCM-3680 */
	/* Request the controllers address space */
printk(" can%d is an PCM-3680, allocate iomem at 0x%x\n", minor, Base[minor]);
	if(NULL == request_mem_region(Base[minor], can_range[minor], "CAN-IO")){
	    DBGprint(DBG_DATA,("Request_mem-Region CAN-IO failed at 0x%x\n",
		    Base[minor]));
	    return -EBUSY;
	}
    }


    can_base[minor] = ioremap(Base[minor], can_range[minor]);
    /* now the virtual address can be used for the register access macros */

    /* Signature of the CPC-104 Board
     * byte offset	value description
	0		0x55 for Read / acts as control register for Write
	1		0xaa
	2		occupied memory range in 512 byte units (0x01)
	3		0xcb
	4		CAN controller id
		    1 - 82527
		    2 - 82c200
		    8 - SJA1000
	6		Status register
      */
	

    if(Base[minor] < 0xD8000) {
	/* By definition a EMS CPC-104 */
	/* printk(" Signature = 0x%x\n", ioread32(can_base[minor])); */
	if(0xCB01AA55 == ioread32(can_base[minor])) {
		/* Hardware reset of CAN controller.
		 * The minimum reset time for the individual controllers
		 * is generated by logic on CPC-104.
		 */
		writeb(0, can_base[minor]);
		mdelay(10);
		/* Map CAN controller into memory address range. */
		writeb(3, can_base[minor]);
		/* CAN controller is at board + 0x100 */
		can_base[minor] = can_base[minor] + 0x100; 
	} else {
		printk(KERN_INFO "CPC-104 wrong card Signature\n");
		/* release I/O memory mapping -> release virtual memory */
		iounmap(can_base[minor]);
		/* Release the memory region */
		release_mem_region(Base[minor], can_range[minor]);
		return -EBUSY;
	}
    } else {
	/* By definition a Advantech PCM-3680 */
	if( Base[minor] & 0x200 ) {
		/* printk("Resetting Advantech Pcm-3680 [contr 1]\n"); */
		/* perform HW reset 2. contr*/
		writeb(0xff, can_base[minor] + 0x300);
	} else {
		/* printk("Resetting Advantech Pcm-3680 [contr 0]\n"); */
		/* perform HW reset 1. contr*/
		writeb(0xff, can_base[minor] + 0x100);
	}
        mdelay(100);
    }


    if( IRQ[minor] > 0 || IRQ[minor] > MAX_IRQNUMBER ){
        int err;
	err = request_irq( IRQ[minor], CAN_Interrupt, SA_SHIRQ, 
				"Can", &Can_minors[minor]);
        if( !err ){
	    DBGprint(DBG_BRANCH,("Requested IRQ: %d @ 0x%lx",
				    IRQ[minor], (unsigned long)CAN_Interrupt));
	    IRQ_requested[minor] = 1;
	} else {
	    release_mem_region(Base[minor], can_range[minor]);
	    DBGout(); return -EBUSY;
	}
    } else {
	/* Invalid IRQ number in /proc/.../IRQ */
	release_mem_region(Base[minor], can_range[minor]);
	DBGout(); return -EBUSY;
    }
    DBGout(); return 0;
}
Example #21
0
int can_Config(
	struct inode *inode,
	struct file *file,
	int target,
	unsigned long val1,
	unsigned long val2
	)
{
unsigned int minor = iminor(inode);
int rx_fifo = ((struct _instance_data *)(file->private_data))->rx_index;
int ret;

    DBGin();
    ret = -EINVAL;
    switch(target) {
	case CONF_ACC:		/* set the first code/mask pair */
#if defined(IMX35) || defined(IMX25)
	    ret = CAN_SetMask(minor, 0, val2, val1);
#else
	    ret = CAN_SetMask(minor, val2, val1);		
#endif
	    break;
	case CONF_ACCM:		/* set the first mask only */
#if defined(IMX35) || defined(IMX25)
	    ret = CAN_SetMask(minor, 0, AccCode[minor][0], val1);
#else
	    ret = CAN_SetMask(minor, AccCode[minor], val1);		
#endif
	    break;
	case CONF_ACCC:		/* the first code only */
#if defined(IMX35) || defined(IMX25)
	    ret = CAN_SetMask(minor, 0, val1, AccMask[minor][0]);
#else
	    ret = CAN_SetMask(minor, val1, AccMask[minor]);		
#endif
	    break;

#if defined(IMX35) || defined(IMX25)
	case CONF_ACC1:		/* set the first additional code/mask pair */
	    ret = CAN_SetMask(minor, 1, val2, val1);
	    break;
	case CONF_ACC2:
	    ret = CAN_SetMask(minor, 2, val2, val1);
	    break;
	case CONF_ACC3:
	    ret = CAN_SetMask(minor, 3, val2, val1);
	    break;
	case CONF_ACC4:
	    ret = CAN_SetMask(minor, 4, val2, val1);
	    break;
	case CONF_ACC5:
	    ret = CAN_SetMask(minor, 5, val2, val1);
	    break;
	case CONF_ACC6:
	    ret = CAN_SetMask(minor, 6, val2, val1);
	    break;
	case CONF_ACC7:
	    ret = CAN_SetMask(minor, 7, val2, val1);
	    break;
#endif
	case CONF_TIMING:
	    ret = CAN_SetTiming(minor,(int) val1);   
	    if (0 == ret) {
		Baud[minor] = val1;
	    } else {
		ret = -EINVAL;
	    }
	   break;                    
	case CONF_OMODE:
	    ret = CAN_SetOMode( minor, (int) val1);
	    break;			
#if CAN_USE_FILTER
	case CONF_FILTER:
	    Can_FilterOnOff( minor, (int) val1 );
	    break;
	case CONF_FENABLE:
	    Can_FilterMessage( minor, (int) val1, 1);
	    break;
	case CONF_FDISABLE:
	    Can_FilterMessage( minor, (int) val1, 0);
	    break;
#endif
	case CONF_LISTEN_ONLY_MODE:
	    ret = CAN_SetListenOnlyMode( minor, (int) val1);
	    break;
	case CONF_SELF_RECEPTION:
	    DBGprint(DBG_DATA,
	    ("setting selfreception of minor %d to %d\n", minor, (int)val1));
	    selfreception[minor][rx_fifo] = (int)val1;
	    ret = 0;
	    break;
	case CONF_TIMESTAMP:
	    use_timestamp[minor] = (int)val1;
	    ret = 0;
	    break;
	case CONF_WAKEUP:
	    wakeup[minor] = (int)val1;
	    ret = 0;
	    break;
	case CONF_BTR:
	    ret = CAN_SetBTR(minor, (int)val1, (int)val2);
	    break;

	default:
	    ret = -EINVAL;
    }
    DBGout();
    return ret;
}
Example #22
0
int CAN_VendorInit (int minor)
{
    DBGin();
    can_range[minor] = CAN_RANGE;

   /* Request the controllers address space
     * Nothing to do for the AT-CAN-MINI, we have io-addresses 
     * can_base in this case stores a (unsigned char *)
     *
     * CAN_PORT_IO only uses Base[]
     */


   /*

    int request_irq(unsigned int irq,			// interrupt number  
              void (*handler)(int, void *, struct pt_regs *), // pointer to ISR
		              irq, dev_id, registers on stack
              unsigned long irqflags, const char *devname,
              void *dev_id);

       dev_id - The device ID of this handler (see below).       
       This parameter is usually set to NULL,
       but should be non-null if you wish to do  IRQ  sharing.
       This  doesn't  matter when hooking the
       interrupt, but is required so  that,  when  free_irq()  is
       called,  the  correct driver is unhooked.  Since this is a
       void *, it can point to anything (such  as  a  device-spe-
       cific  structure,  or even empty space), but make sure you
       pass the same pointer to free_irq().

       If the kernel receives an interrupt he knows
       how often it was registered,
       and calls the ISR for each registered interrupt.
       In this case, can4linux, for example
       every time with a different pointer to Can_minors[]
       contaiing the device minor which has registered.
       The ISR should now check this CAN controller relaed to the minor
       number, if it was the cause of the interrupt.

    */

    /* test for valid IRQ number in /proc/sys/.../IRQ */
    if( IRQ[minor] > 0 && IRQ[minor] < MAX_IRQNUMBER ){
        int err;

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) 
	err = request_irq( IRQ[minor], CAN_Interrupt, IRQF_SHARED, 
				"Can", &Can_minors[minor]);
#else
	err = request_irq( IRQ[minor], CAN_Interrupt, SA_SHIRQ, 
				"Can", &Can_minors[minor]);
#endif

        if( !err ){
	    DBGprint(DBG_BRANCH,("Requested IRQ: %d @ 0x%lx",
				    IRQ[minor], (unsigned long)CAN_Interrupt));
	    IRQ_requested[minor] = 1;
	} else {
	    DBGout(); return -EBUSY;
	}
    } else {
	/* Invalid IRQ number in /proc/.../IRQ */
	DBGout(); return -EBUSY;
    }

    DBGout(); return 0;
}