📄 pci_can.c
字号:
#ifdef CAN_DEBUG
printk( "CAN PROTOCOL 20A!\n" );
#endif
can_put_reg( port, CAN_CR, 1 );
can_put_reg( port, CAN_BTR0, bt0 );
can_put_reg( port, CAN_BTR1, bt1 );
if( bt0 != can_get_reg( port, CAN_BTR0 ) )
{
#ifdef CAN_DEBUG
printk( "Set port%d's baudrate0 error, bt0=%x\n",
port, can_get_reg( port, CAN_BTR0 ) );
#endif
return 0;
}
if( bt1 != can_get_reg( port, CAN_BTR1 ) )
{
#ifdef CAN_DEBUG
printk(" Set port%d's baudrate 1 error, bt1=%x\n",
port, can_get_reg( port, CAN_BTR1 ) );
#endif
return 0;
}
can_put_reg( port, CAN_ACR, param->accode[ 0 ] );
can_put_reg( port, CAN_AMR, param->accmask[ 0 ] );
can_put_reg( port, CAN_OCR, 0x1a );
can_put_reg( port, CAN_CDR, can_get_reg( port, CAN_CDR ) & 0x7f );
#ifdef CAN_DEBUG
printk( "setup port %x to 20A\n", port );
#endif
can_put_reg( port, CAN_CR, can_get_reg( port, CAN_CR ) & 0xfe );
udelay(100);
can_ena_irq( port, 1 );
}
break;
case CAN_PROTOCOL_20B:
{
can_put_reg( port, CAN_MOD, CAN_RESET_REQUEST );
can_put_reg( port, CAN_BTR0, bt0 );
can_put_reg( port, CAN_BTR1, bt1 );
if( bt0 != can_get_reg( port, CAN_BTR0 ) )
return ( 0 );
if( bt1 != can_get_reg( port, CAN_BTR1 ) )
return ( 0 );
temp = can_get_reg(port, CAN_MOD);
if(param->filtertype==0)
temp |= 0x08;
else
temp &= 0xf7;
can_put_reg(
port,
CAN_CDR,
can_get_reg( port, CAN_CDR)|0x80 );
can_put_reg(
port,
CAN_MOD,
temp );//set filter mode
for( i = 0; i < 4; i++ )
can_put_reg( port, CAN_ACR0+i, param->accode[ i ] );
for( i = 0; i < 4; i++ )
can_put_reg( port, CAN_AMR0+i, param->accmask[ i ] );
can_put_reg( port, CAN_IER, param->interruptmask );
can_put_reg( port, CAN_OCR, 0xfa );
#ifdef CAN_DEBUG
printk( "setup port %x to 20B\n",port );
printk( "param->interruptmask=%x, get_reg(port%x, CAN_IER)=%x\n",
param->interruptmask, port, can_get_reg( port, CAN_IER ) );
#endif
can_put_reg(
port,
CAN_MOD,
can_get_reg( port, CAN_MOD ) & 0xfe );//set normal
udelay( 1000 );
can_ena_irq( port, 1 );
}
break;
default:
{
return -1;
}
}
return 1;
}
// ****************************************************************************
// Design Notes: Transmit message to read FIFO
//-----------------------------------------------------------------------------
static int can_rx_message ( int port )
{
if ( port < 0 || port >= MAX_DEVICE )
{
#ifdef CAN_DEBUG
printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
return 0;
}
if ( can_get_reg( port, CAN_SR ) & CAN_RECEIVE_BUFFER_STATUS )
{
/* message available */
int iii;
unsigned int temp1,temp2;
can_msg_t *msg;
#ifdef CAN_DEBUG
printk( "in function can_rx_message begin: port = %d\n", port );
#endif
msg = ( can_msg_t * )&RdFifo[ port ].buffer[ RdFifo[ port ].head ];
if( can_state[ port ].protocol == CAN_PROTOCOL_20A )
{
temp1 = can_get_reg( port, CAN_RX + 0 );
temp2 = can_get_reg( port, CAN_RX + 1 );
msg->id = temp1;
msg->id <<= 3;
msg->id |= temp2 >> 5;
msg->rtr = (temp2 >> 4) & 1;
msg->ff = 0;
msg->dlen = temp2 & 0x0f;
for ( iii = 0; iii < msg->dlen; iii++ )
msg->data[ iii ] = can_get_reg( port, CAN_RX + iii + 2 );
for ( iii = msg->dlen; iii < 8; iii++ )
msg->data[iii] = 0;
}
else
{
//PROTOCOL_20B
temp1 = can_get_reg( port, CAN_RX_EX + 0 );
msg->ff = temp1 & 0x80;
msg->dlen = temp1 & 0x0f;
msg->rtr = (temp1>>6)&1;
if(msg->ff == PELICAN_SFF )
{
temp1 = can_get_reg( port, CAN_RX_EX + 1 );
temp2 = can_get_reg( port, CAN_RX_EX + 2 );
//msg->id = temp2;
msg->id = (unsigned int)temp1 << 3;
//msg->id = ( msg->id << 8 ) + temp1;
msg->id |= temp2 >>5;
for ( iii = 0; iii < msg->dlen; iii++ )
msg->data[ iii ] = can_get_reg( port, CAN_RX_EX + iii + 3 );
for ( iii = msg->dlen; iii < 8; iii++ )
msg->data[iii] = 0;
}
else
{
temp1 = can_get_reg( port, CAN_RX_EX+4 );
//msg->id = temp1;
msg->id = (unsigned int)temp1>>3;
temp1 = can_get_reg( port, CAN_RX_EX+3 );
//msg->id = ( msg->id << 8 ) + temp1;
msg->id |= temp1<<5;
temp1 = can_get_reg( port, CAN_RX_EX+2 );
//msg->id = ( msg->id << 8 ) + temp1;
msg->id |= temp1<<13;
temp1 = can_get_reg( port, CAN_RX_EX+1 );
//msg->id = ( msg->id << 8 ) + temp1;
msg->id |= temp1<<21;
for ( iii = 0; iii < msg->dlen; iii++ )
msg->data[ iii ] = can_get_reg( port, CAN_RX_EX + iii + 5 );
for ( iii = msg->dlen; iii < 8; iii++ )
msg->data[ iii ] = 0;
}
}
RdFifo[ port ].head += CAN_MSG_LEN;
RdFifo[ port ].head %= RD_FIFO_LEN;
if ( RdFifo[ port ].size <= RD_FIFO_LEN-CAN_MSG_LEN )
{
/* fifo is not full */
RdFifo[ port ].size += CAN_MSG_LEN;
}
else
{
/* the oldest msg was overwritten */
/* mark fifo overflow, not (yet) used */
//RdFifo0.status = FIFO_OVERFLOW;
RdFifo[ port ].size = RD_FIFO_LEN;
RdFifo[ port ].tail += CAN_MSG_LEN;
RdFifo[ port ].tail %= RD_FIFO_LEN;
}
/* free the RX buffer, avoid CAN overrun */
can_put_reg( port, CAN_CMR, CAN_RELEASE_RECEIVE_BUFFER );
#ifdef CAN_DEBUG
printk( "in function can_rx_message over:\n" );
printk( "the msg.id =%x, msg.dlen=%d, msg.ff=%d,msg.data=%x%x%x%x%x%x%x%x\n",
msg->id, msg->dlen, msg->ff,
msg->data[0], msg->data[1], msg->data[2],
msg->data[3], msg->data[4], msg->data[5],
msg->data[6], msg->data[7] );
#endif
return 1;
}
else
{
return 0;
}
}
// ****************************************************************************
// Design Notes:
//-----------------------------------------------------------------------------
void
can_interrupt (
int irq,
void *dev_id,
struct pt_regs *regs )
{
unsigned char can_ir;
int port;
int * pport;
int i;
int got_message[MAX_DEVICE];
pport = (int *)dev_id;
port = *pport;
#ifdef CAN_DEBUG
printk( "in can_interrupt function. the port=%d\n", port );
#endif
for( i=0; i<findnum; i++)
{
got_message[i]=0;
can_ir = can_get_reg(i, CAN_IR);
if( can_ir & CAN_RECEIVE_INT )
{
#ifdef CAN_DEBUG
printk( "in function can_irq_service start receive, port = %d\n", port );
#endif
while ( can_rx_message( i ) )
got_message[i]++;
}
/* wake up the process blocked by read (if data available)*/
if ( got_message[i] )
{
switch( i )
{
case 0:
wake_up_interruptible( &RdWaitQ0 );
break;
case 1:
wake_up_interruptible( &RdWaitQ1 );
break;
case 2:
wake_up_interruptible( &RdWaitQ2 );
break;
case 3:
wake_up_interruptible( &RdWaitQ3 );
break;
case 4:
wake_up_interruptible( &RdWaitQ4 );
break;
case 5:
wake_up_interruptible( &RdWaitQ5 );
break;
case 6:
wake_up_interruptible( &RdWaitQ6 );
break;
case 7:
wake_up_interruptible( &RdWaitQ7 );
break;
case 8:
wake_up_interruptible( &RdWaitQ8 );
break;
case 9:
wake_up_interruptible( &RdWaitQ9 );
break;
case 10:
wake_up_interruptible( &RdWaitQ10 );
break;
case 11:
wake_up_interruptible( &RdWaitQ11 );
break;
}
}
}
#ifdef CAN_DEBUG
printk( "in function can_interrupt\n" );
#endif
}
// ****************************************************************************
// Design Notes:
//-----------------------------------------------------------------------------
int
can_open (
struct inode *inode,
struct file *file )
{
int Minor;
// int retval = 0;
//char name[10];
Minor = MINOR( inode->i_rdev ); // major = inode->i_rdev >> 8;
if ( Minor < 0 || Minor >= findnum )
{
#ifdef CAN_DEBUG
printk( "in can_get_reg function the port=%d is error!\n", Minor );
#endif
return -EINVAL;
}
/* if( hasint[Minor] )
free_irq( irq[Minor], (void*)(&minorport[Minor]) );
memset( name, 0, 10 );
sprintf( name, "can%d", Minor );
retval =
request_irq(
irq[Minor],
can_interrupt,
SA_SHIRQ,
name,
(void*)(&minorport[ Minor ]) );
if ( retval < 0 )
{
#ifdef CAN_DEBUG
printk("%s: request irq falled with %d\n",
DEVICE_NAME,
retval);
#endif
return -EINVAL;
}
hasint[Minor] = 1;
*/ MOD_INC_USE_COUNT;
return SUCCESS;
}
/*******************************************************************/
/* This function is called when a process closes the
* device file. It doesn't have a return value in
* version 2.0.x because it can't fail (you must ALWAYS
* be able to close a device). In version 2.2.x it is
* allowed to fail - but we won't let it.
*/
// ****************************************************************************
// Design Notes:
//-----------------------------------------------------------------------------
int
can_release (
struct inode *inode,
struct file *file )
{
/* If there are messages pending,
* sleep until ready, timed out or error.
* The longest CAN message is about 130 bits,
* at 20 kBit/s -> 6.5 ms.
* Transmitting the full fifo (100 msg) takes
* 0.65 seconds at bus idle.
*
* A timeout of 2 seconds should be ok.
*/
int Minor;
Minor = MINOR( inode->i_rdev ); // major = inode->i_rdev >> 8;
if ( Minor < 0 || Minor >= findnum )
{
#ifdef CAN_DEBUG
printk( "in can_get_reg function the port=%d is error!\n", Minor );
#endif
return -EINVAL;
}
// free_irq( irq[Minor], (void*)(&minorport[ Minor ]) );
// hasint[Minor] = 0;
MOD_DEC_USE_COUNT;
can_ena_irq(Minor, 0);
return 0;
}
// ****************************************************************************
// Design Notes: read from port 0.
//-----------------------------------------------------------------------------
ssize_t
can_read (
struct file *file,
char *buffer,
size_t length,
loff_t *offset )
{
int bytes_read = 0;
int iii;
unsigned char msg[ CAN_MSG_LEN ];
int port;
/* Don't use pread()/pwrite() system calls */
if ( offset != &file->f_pos )
return -ESPIPE;
port = MINOR( file->f_dentry->d_inode->i_rdev ); // major = inode->i_rdev >> 8;
if ( port < 0 || port >= findnum )
{
#ifdef CAN_DEBUG
printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
return -EINVAL;
}
//printk("in the read function the port is %d\n", port );
/* can_ena_irq( port, 0 );
if ( can_get_reg( port, CAN_SR ) & 0x01 )
{
unsigned char can_ir = can_get_reg( port, CAN_IR ) & 0x1F;
can_irq_service( can_ir, port );
}
can_ena_irq( port, 1 );
*/ if ( length < CAN_MSG_LEN )
return -EINVAL;
while ( 0 == RdFifo[ port ].size )
{
/* CAN bus error occured */
if ( can_is_resetted( port ) )
return -EIO;
/* if opened nonblocking, return error (try again!)*/
if ( file->f_flags & O_NONBLOCK )
return -EAGAIN;
/* This function puts the current process,
* including any system calls, such as us, to sleep.
* Execution will be resumed right after the function
* call, either because somebody called
* wake_up(&WaitQ) (only interrupt does that)
* or when a signal, such as Ctrl-C,
* is sent to the process
*/
switch( port )
{
case 0:
interruptible_sleep_on( &RdWaitQ0 );
break;
case 1:
interruptible_sleep_on( &RdWaitQ1 );
break;
case 2:
interruptible_sleep_on( &RdWaitQ2 );
break;
case 3:
interruptible_sleep_on( &RdWaitQ3 );
break;
case 4:
interruptible_sleep_on( &RdWaitQ4 );
break;
case 5:
interruptible_sleep_on( &RdWaitQ5 );
break;
case 6:
interruptible_sleep_on( &RdWaitQ6 );
break;
case 7:
interruptible_sleep_on( &RdWaitQ7 );
break;
case 8:
interruptible_sleep_on( &RdWaitQ8 );
break;
case 9:
interruptible_sleep_on( &RdWaitQ9 );
break;
case 10:
interruptible_sleep_on( &RdWaitQ10 );
break;
case 11:
interruptible_sleep_on( &RdWaitQ11 );
break;
}
/* If we woke up because we got a signal we're not
* blocking, return -EINTR (fail the system call).
* This allows processes to be killed or stopped.
*/
if ( signal_pending( current ) )
return -EINTR;
}
/* Actually put one msg from fifo into the driver buffer */
can_ena_irq( port, 0 );
for ( iii = 0; iii < CAN_MSG_LEN; iii++ )
{
msg[ iii ] = RdFifo[ port ].buffer[ RdFifo[ port ].tail ];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -