コード例 #1
0
/* is not very useful! use it if you are sure the tx queu is empty */
int can_Send(struct inode *inode, canmsg_t *Tx)
{
unsigned int minor = MINOR(inode->i_rdev);	
canmsg_t tx;

    if( verify_area(VERIFY_READ,Tx,sizeof(canmsg_t)) ) {
	    return -EINVAL;
    }
    __lddk_copy_from_user((canmsg_t *) &tx, (canmsg_t *) Tx,sizeof(canmsg_t));
    return CAN_SendMessage(minor, &tx);
}
コード例 #2
0
ファイル: ioctl.c プロジェクト: JonahLiu/advcan
/* is not very useful! use it if you are sure the tx queue is empty */
int can_Send(struct inode *inode, canmsg_t *Tx)
{
unsigned int minor = iminor(inode);	
canmsg_t tx;
unsigned long _cnt;

    if( !access_ok(VERIFY_READ, Tx, sizeof(canmsg_t)) ) {
	    return -EINVAL;
    }
    __lddk_copy_from_user((canmsg_t *)&tx, (canmsg_t *)Tx, sizeof(canmsg_t));
    return CAN_SendMessage(minor, &tx);
}
コード例 #3
0
ファイル: ioctl.c プロジェクト: JonahLiu/advcan
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;
}
コード例 #4
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;
}
コード例 #5
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;
}
コード例 #6
0
ファイル: write.c プロジェクト: 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++;
    }