📄 pci_can.c
字号:
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 + -