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

📄 pci_can.c

📁 linux下PCI_CAN 的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		RdFifo[ port ].tail++;
		RdFifo[ port ].tail %= RD_FIFO_LEN; /* wrap around pointer */
		RdFifo[ port ].size--;
	}
	/* enable CAN irq in case buffer is paged out */
	can_ena_irq( port, 1 );
        
	/* transfer the message into the user space */
	iii = CAN_MSG_LEN;
	copy_to_user( buffer, (void *)msg, (size_t)iii );
	length -= CAN_MSG_LEN;
	bytes_read +=CAN_MSG_LEN;
  
	return bytes_read; 
}

// ****************************************************************************
// Design Notes:  write to port 0.
//-----------------------------------------------------------------------------
ssize_t
can_write (
	struct file *file,
	const char *buffer,    /* The buffer */
	size_t length,   /* The length of the buffer */
	loff_t *offset )  /* Our offset in the file */
{

	int iii;
	unsigned char mymsg[ CAN_MSG_LEN ];
	unsigned temp;
	can_msg_t *pmsg, *msg;
	int port;
	unsigned char status;
#ifdef CAN_DEBUG
	printk( "in funtion can_write!\n" );
#endif
	/* 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;
	//printk("the port is %d in function write\n", port );
	if ( port < 0 || port >= findnum )
	{
#ifdef CAN_DEBUG
		printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
		return -EINVAL;
	}
	/* CAN bus error occured */
	if ( can_is_resetted( port ) )
		return -EIO;
  
	/* each read call give one CAN msg */
	if ( length < CAN_MSG_LEN )
		return -EINVAL;
  
	/* Actually put the data into the driver buffer */
	copy_from_user( mymsg, buffer, CAN_MSG_LEN );
	pmsg = (can_msg_t*)mymsg;
	msg = pmsg;
#ifdef CAN_DEBUG
	printk("in funtion can_write:copy from user!\n");
	printk("msg.id =%x, msg.dlen=%d, msg.data =%x%x%x%x%x%x%x%x\n",
		pmsg->id, pmsg->dlen, pmsg->data[0],
		pmsg->data[1], pmsg->data[2], pmsg->data[3],
		pmsg->data[4], pmsg->data[5], pmsg->data[6],
		pmsg->data[7]);
#endif
	if( can_get_reg(port, CAN_SR) & CAN_TRANSMIT_BUFFER_ACCESS )
	{
		
		if(can_state[port].protocol == CAN_PROTOCOL_20A)
		{
			temp = (unsigned int)msg->id>>3;
			can_put_reg(port, CAN_TX+0, temp);
			temp = msg->id & 0x07;
			temp <<= 5;
			if( msg->rtr == 1 )
			{
				temp |= 0x10;
			}
			temp += msg->dlen;
			can_put_reg(port, CAN_TX+1, temp);
			for( iii=0; iii<msg->dlen; iii++)
				can_put_reg(
					port,
					CAN_TX+iii+2,
					msg->data[iii]);
		}
		else
		{
			temp = 0;
			temp |= msg->dlen;
			if(msg->rtr==1)
				temp |= 1<<6;
			if(msg->ff == PELICAN_SFF )
			{
				can_put_reg(port, CAN_TX_EX, temp);
				//temp = msg->id & 0xff;
				temp = 0;
				temp = (unsigned int)(msg->id>>3);
				can_put_reg(port, CAN_TX_EX+1, temp);
				temp = 0;
				temp = (msg->id & 0x07);
				temp <<=5;
				//temp = (msg->id>>8) & 0xff;
				can_put_reg(port, CAN_TX_EX+2, temp);
				for(iii=0; iii<msg->dlen; iii++)
					can_put_reg(
						port,
						CAN_TX_EX+iii+3,
						msg->data[iii]);
			}
			else
			{
				temp |= 1<<7;
				can_put_reg(port, CAN_TX_EX, temp);
				//temp = msg->id & 0xff;
				temp = (unsigned int)(msg->id>>21);
				can_put_reg(port, CAN_TX_EX+1, temp);
				//temp = (msg->id>>8) & 0xff;
				temp = (unsigned int)(msg->id & 0x1fffff);
				temp >>= 13;
				can_put_reg(port, CAN_TX_EX+2, temp);
				//temp = (msg->id>>16) & 0xff;
				temp = (unsigned int)(msg->id & 0x1fff);
				temp >>=5;
				can_put_reg(port, CAN_TX_EX+3, temp);
				//temp = (msg->id>>24) & 0xff;
				temp = (unsigned int)(msg->id & 0x1f);
				temp <<= 3;
				can_put_reg(port, CAN_TX_EX+4, temp);
				for(iii=0; iii<msg->dlen; iii++)
					can_put_reg(
						port,
						CAN_TX_EX+iii+5,
						msg->data[iii]);
			}			
		}
		can_put_reg(
			port,
			CAN_CMR,
			CAN_TRANSMISSION_REQUEST);
		while(1)
		{
			status = can_get_reg(port, CAN_SR);
			if(status & 0x08)
				return CAN_MSG_LEN;
			if(status & 0xc0)
				return 0;
		}
	}
	else
		return 0;
		 
}

/* This function is called whenever a process tries to
 * do an ioctl on our device file. We get two extra
 * parameters (additional to the inode and file
 * structures, which all device functions get): the number
 * of the ioctl called and the parameter given to the
 * ioctl function.
 *
 * If the ioctl is write or read/write (meaning output
 * is returned to the calling process), the ioctl call
 * returns the output of this function.
 */

// ****************************************************************************
// Design Notes:  Control routine.
//-----------------------------------------------------------------------------
int
can_ioctl (
	struct inode *inode,
	struct file *file,
	unsigned int ioctl_num,
	unsigned long ioctl_param )
{
	/* Switch according to the ioctl called */
	int Minor;
   
	Minor = MINOR(inode->i_rdev);
	switch ( ioctl_num )
	{
	case IOCTL_SET_CAN:
		{
			return can_setup( Minor, (CAN_STRUCT *)ioctl_param );
		}
	case IOCTL_RESET_CAN:
		{
			can_reset( Minor );
		}
		return SUCCESS;
	}
	return -EINVAL;
}


/*******************************************************************/
/* This structure will hold the functions to be
 * called when a process does something to the device
 * we created. Since a pointer to this structure is
 * kept in the devices table, it can't be local to
 * init_module. NULL is for unimplemented functions.
 */

struct file_operations Fops =
{
	read:	   can_read,
	write:   can_write,
	ioctl:   can_ioctl,
	open:	   can_open,
	release: can_release,
};


/*******************************************************************/
/* The kernel module interface functions:
 * init_module() and cleanup_module()
 */

/* Initialize the module, called from insmod / modprobe / kerneld etc.
 * - find the CAN interface
 * - register the character device
 * - request the io region
 */

static int __init can_probe (struct pci_dev *dev, const struct pci_device_id *id )  //zdd modify
{
	int retval = 0;
	unsigned int address1, address2, address3;
	int i=0, index=0, j=0;
	unsigned char temp, busnum, devnum, intline;
	unsigned char tempbus[MAX_CARDS], tempdev[MAX_CARDS];
	unsigned short deviceID;//, vendorID;
	char name[10];
	printk("\n=====================================================\n");
	printk("PCI CAN Communication Card Driver.\nVersion: %s (%s)\n", 
		ADVANTECH_CAN_VER, ADVANTECH_CAN_REV);
	printk("Support:PCI-1680 and MIC-3680\n");
	printk("ADVANTECH Co,Ltd.\n");
	printk("=====================================================\n");
	//deviceID = 0x1680;
	deviceID = id->device;
	//vendorID = 0x13FE;
	findnum = 0;
	for ( i = 0; i < MAX_CARDS; i++ )
	{
		tempbus[ i ] = tempdev[ i ] = 0;
	}
#ifdef CONFIG_PCI
   if(pci_present())
#endif
   {
		for( i = 0; i < MAX_CARDS; i++ )
		{
			
			if( pcibios_find_device(ADVANTECH_VANDORID,deviceID,index,&busnum,&devnum ) != 0 )
			{
				index = 0;
            			continue;				
			}
			else
			{
				for( j = 0; j < i; j++ )
				{
					if( busnum == tempbus[ j ] && devnum == tempdev[ j ] )
						goto finddone;
				}
				tempbus[ i ] = busnum;
				tempdev[ i ] = devnum;
#ifdef CAN_DEBUG
				printk("Get the pci device, busnum = %d, devnum = %d\n", busnum, devnum);
#endif
				pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_2, &address1);
				if(address1 == 0xffffffff)
				{
					;
#ifdef CAN_DEBUG
					printk("Can't get the address2 of this card!\n");
#endif
				}
				else
				{
					iobase[ (2*index) ] = address1 & PCI_BASE_ADDRESS_IO_MASK;
					
					findnum++;
#ifdef CAN_DEBUG
					printk("The %dth device base address is%x\n",	(2*index), iobase[ (2*index) ] );
#endif
				}
				pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_3, &address2);
				if(address2 == 0xffffffff)
				{
					;
#ifdef CAN_DEBUG
					printk("Can't get the adress3 of this card!\n");
#endif
				}
				else
				{
					iobase[ (2*index + 1) ] = address2 & PCI_BASE_ADDRESS_IO_MASK;
					findnum++;
#ifdef CAN_DEBUG
					printk("The %dth device base address is %x\n",
						(2*index + 1 ),
						iobase[ (2*index + 1) ]);
#endif
				}
				pcibios_read_config_dword(busnum, devnum, PCI_BASE_ADDRESS_4, &address3);
				if(address3 == 0xffffffff)
				{
					;
#ifdef CAN_DEBUG
					printk("Can't get the address4 of this card!\n");
#endif
				}
				else
				{
					iohwbase[ ( 2*index) ] = address3 & PCI_BASE_ADDRESS_IO_MASK;	
					iohwbase[ (2*index + 1) ] = (address3 & PCI_BASE_ADDRESS_IO_MASK) + 1;
#ifdef CAN_DEBUG
					printk("This %dth device hardware address is %x\n",
						( 2*index ),
						iohwbase[ (2*index) ] );
					printk("This %dth device hardware address is %x\n",
						( 2*index + 1 ),
						iohwbase[ (2*index + 1) ] );
#endif
				}
				pcibios_read_config_byte(busnum, devnum, PCI_INTERRUPT_LINE, &intline);
				if( intline == 0 )
				{
#ifdef CAN_DEBUG
					printk("Can't get the interruptline of this card!\n");
#endif
				}
				else
				{
					irq[ (2*index) ] = intline;
					irq[ (2*index + 1) ] = intline;
#ifdef CAN_DEBUG
					printk("The %dth device interruptline is %d\n",
						( 2*index ),
						irq[ (2*index) ] );
					printk("The %dth device interruptline is %d\n",
						( 2*index + 1 ),
						irq[ (2*index + 1) ] );
#endif
					
				}
				index++;
			}	
		}
	}
	
finddone:
	printk( "the find port is %d\n", findnum );
	for ( i = 0; i < findnum; i++ )
	{
		if( iobase[ i ] == 0 ||
			iohwbase[ i ] == 0 ) 
		{
	#ifdef CAN_DEBUG
			printk("The %dth device io address error!\n", i);
	#endif
			return(0);
		}
		can_reset( i );
		udelay( 10000 );  
		temp = can_get_reg( i, CAN_CR );
#ifdef CAN_DEBUG
		printk("after reset port%d reg = %x\n", i, temp);
#endif

		if( 0x21 != ( can_get_reg( i, CAN_CR ) &0x21 ) )
		{
#ifdef CAN_DEBUG
			printk("Can't find Advantech CAN communication card's port%d!\n",
				i );
#endif
			goto out;
		}
#ifdef CAN_DEBUG
		printk("Port 0 SR = %x, IR = %x\n",
			can_get_reg( i, CAN_SR ),
			can_get_reg( i, CAN_IR ) );
#endif
		if( 0x0c != can_get_reg( i, CAN_SR )) goto out;
		if( 0xe0 != can_get_reg( i, CAN_IR )) goto out;
#ifdef CAN_DEBUG
	printk("port 0 btr0 =%d, btr1 = %d\n",
		can_get_reg( i, CAN_BTR0 ),
		can_get_reg( i,CAN_BTR1 ) );
#endif
	}
	for( i=0; i<findnum; i++)
	{
		memset( name, 0, 10 );
		sprintf( name, "can%d", i );
		retval =
			request_irq(
				irq[i],
				can_interrupt,
				SA_SHIRQ,
				name,
				(void*)(&minorport[ i ]) );
		if ( retval < 0 )
		{
#ifdef CAN_DEBUG
			printk("%s: request irq falled with %d\n",
				name,
				retval);
#endif
			return -EINVAL;
		}
	}
	major = retval = 
		register_chrdev(
			0,
			DEVICE_NAME,
			&Fops );
 	
	/* Negative values signify an error */
	if ( retval < 0 )
	{
#ifdef CAN_DEBUG
		printk ( "%s: register_chrdev() failed with %d\n",
			DEVICE_NAME,
			retval );
#endif
		goto out;
	}
	else
	{
#ifdef CAN_DEBUG
		printk("The major number is %d\n", major );
#endif
	}
  
	printk("\nAdvantech CAN Communication card driver loaded!\n\n");
	return 0;
 
out:    
	return -ENODEV;
}


/*******************************************************************/
/* Cleanup, called from rmmod */
static void __exit can_remove ( struct pci_dev *dev) //zdd modified
{
	int ret;
	int i;
	can_reset(0);
	can_reset(1);  
	for( i=0; i<findnum; i++)
		free_irq( irq[i], (void*)(&minorport[i]) );
	/* Unregister the device */
	ret = unregister_chrdev( major, DEVICE_NAME );
  
	/* If there's an error, report it */
#ifdef CAN_DEBUG
	if ( ret < 0 )
		printk( "Error in unregister_chrdev(): %d\n", ret );
	else
		printk("Advantech pci1680 cleanup successful!\n");
#endif
	
}
MODULE_AUTHOR ("jerry bai");
module_init(can_init);
module_exit(can_cleanup);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -