⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci_can.c

📁 linux下PCI_CAN 的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
#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 + -