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

📄 pci_can.c

📁 linux下PCI_CAN 的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
// #############################################################################
// *****************************************************************************
//                  Copyright ( c ) 2003, Advantech Automation Corp.
//      THIS IS AN UNPUBLISHED WORK CONTAINING CONFIDENTIAL AND PROPRIETARY
//               INFORMATION WHICH IS THE PROPERTY OF ADVANTECH AUTOMATION CORP.
//
//    ANY DISCLOSURE, USE, OR REPRODUCTION, WITHOUT WRITTEN AUTHORIZATION FROM
//               ADVANTECH AUTOMATION CORP., IS STRICTLY PROHIBITED.
// *****************************************************************************
// #############################################################################
/***
 * File:     adv_can.c
 * Author:   Jerry Bai
 * Created:  2004-5-20
 * Revision: 1.00 
 * Description:  PCI1680 CAN Bus Driver
 * FEXPORT FUNCTION:
 *    open, ioctl, read, write, close
 *
 * HISTORY:
 *    2004-5-20 Created by Jerry
 * 
 * Description:
 *
 * Driver configuration section.  Here are the various options:
 *
 * io:    the io address of the card
 *	       
 * irq0:  the interrupt number of channel 0
 *
 * irq1:  the interrupt number of channel 1
 *
 * major: driver major number
 *
 * insmod example:
 *        insmod adv_can.o io=0xda00 irq0=7 irq1=9
 *
 */
 
/*
 * Modified by: Zhang dongdong
 *
 * Data:	07/16/04
 *
 * Description: Modified to support board list 
 *		now support pci1680,mic3680
 */

#define ADVANTECH

//#define CAN_DEBUG

static char *ADVANTECH_CAN_VER = "1.00"; 
static char *ADVANTECH_CAN_REV = "2004-05-20";
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/sched.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <asm/atomic.h>

#include <linux/fs.h>
#include <linux/wrapper.h>

#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <asm/uaccess.h>

#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif

#include "adv_can.h"
#include "sja1000.h"


/* Init parameter, usage:
 * "insmod adv_can.o io=0xda00 irq0=7 irq1=9 major = 60"
 */

#define ADVANTECH_VANDORID 0x13FE


#define MAX_CARDS   6
#define MAX_DEVICE  12
//int iobase0  = 0;
//int iobase1  = 0;
int iobase[ MAX_DEVICE ];
int hasint[ MAX_DEVICE ];
//int iohwbase = 0;
int iohwbase[ MAX_DEVICE ];
//int irq      = 0;
int irq[ MAX_DEVICE ];
int major;
int findnum = 0;
int minorport[ MAX_DEVICE ];
MODULE_PARM( findnum,  "i" );
//MODULE_PARM( iobase1,  "i" );
//MODULE_PARM( iohwbase, "i" );
//MODULE_PARM( irq,      "i");
MODULE_PARM( major,    "i" );


/* Queues of waiting processes */
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ0);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ1);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ2);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ3);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ4);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ5);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ6);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ7);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ8);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ9);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ10);
DECLARE_WAIT_QUEUE_HEAD(RdWaitQ11);

DECLARE_WAIT_QUEUE_HEAD(WrWaitQ0);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ1);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ2);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ3);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ4);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ5);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ6);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ7);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ8);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ9);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ10);
DECLARE_WAIT_QUEUE_HEAD(WrWaitQ11);
/* The minor device number for the device. This is
 * global (well, static, which in this context is global
 * within this file) because it has to be accessible
 * both for registration and for release. */
//static int  Minor;


/* Init the CAN controller for a specific bit rate.
 *  * Enable TX and RX interrupts.
 *   * Push/Pull output for 82C250/251 driver circuit.
 *    */

/* The buffer length of message from the can device */
#define RD_FIFO_LEN (200*CAN_MSG_LEN)
#define WR_FIFO_LEN (50*CAN_MSG_LEN)
//zdd add

static struct pci_device_id can_board_table[] = {
	{ADVANTECH_VANDORID, 0x1680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID},
	{ADVANTECH_VANDORID, 0x3680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID},
	{0,}
			
};
static int __init can_probe (struct pci_dev *dev, const struct pci_device_id *id );
static void __exit can_remove (struct pci_dev *dev);

static struct pci_driver can_driver = {
	name:		"pci_can",
	id_table:	can_board_table,
	probe:		can_probe,
	remove:		can_remove,
};
//CAN_INITCLEANUP(can_driver);
static int __init can_init(void){return pci_module_init(&can_driver);}
static void __exit can_cleanup(void){pci_unregister_driver(&can_driver);}
//end

/* the read and write fifos */
typedef struct {
	volatile short head;
	volatile short tail;
	volatile short status;
	volatile short size;
	volatile unsigned char buffer[ RD_FIFO_LEN ];
} can_rd_fifo_t;

typedef struct {
	volatile short head;
	volatile short tail;
	volatile short status;
	volatile short size;
	volatile unsigned char buffer[ WR_FIFO_LEN ];
} can_wr_fifo_t;

#define FIFO_EMPTY   -1
#define FIFO_OK       0
#define FIFO_FULL     1
#define FIFO_OVERFLOW 2

/* these fifos hold our data */
static can_rd_fifo_t RdFifo[ MAX_DEVICE ];
static can_wr_fifo_t WrFifo[ MAX_DEVICE ];
/*state of canbus*/
static CAN_STRUCT can_state[ MAX_DEVICE ];


// ****************************************************************************
// Design Notes:  Initial read and write buffer for port 0
//-----------------------------------------------------------------------------
static void can_init_fifo ( int minor )
{
	int i;
	if ( minor < 0 || minor >= MAX_DEVICE )
	{
#ifdef CAN_DEBUG
		printk( "in can_init_fifo function the minor=%d is error!\n", minor );
#endif
		return;
	}
	
	RdFifo[ minor ].head = RdFifo[ minor ].tail = RdFifo[ minor ].size = 0;
	RdFifo[ minor ].status = FIFO_EMPTY;
	
	WrFifo[ minor ].head = WrFifo[ minor ].tail = WrFifo[ minor ].size = 0;
	WrFifo[ minor ].status = FIFO_EMPTY;
	for( i = 0; i < findnum; i++ )
	{
		minorport[ i ] = i;
	}
}

/*******************************************************************/
/*******************************************************************/
/*******************************************************************/
/* The lowest level access routines for the CAN controller chip.
 * This level handles the physical connection to out PC architech*/


// ****************************************************************************
// Design Notes:  write data to register
//-----------------------------------------------------------------------------
void 
can_put_reg ( 
	int  port, 
	int reg, 
	unsigned char value )
{
	if ( port < 0 || port >= MAX_DEVICE )
	{
#ifdef CAN_DEBUG
		printk( "in can_put_reg function the port=%d is error!\n", port );
#endif
		return;
	}
	outb( value, iobase[ port ] + reg );
}

unsigned char
can_get_reg ( 
	int port,
	int reg )
{
	if ( port < 0 || port >= MAX_DEVICE )
	{
#ifdef CAN_DEBUG
		printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
		return 0xff;
	}
	return inb( iobase[ port ] + reg );
}

// ****************************************************************************
// Design Notes:  reset device pointed by parameter port
//-----------------------------------------------------------------------------
void can_reset ( int port )
{  
	unsigned char temp;

#ifdef CAN_DEBUG
	printk("Enter can_reset, port = %d\n", port);
#endif
	if ( port < 0 || port >= MAX_DEVICE )
	{
#ifdef CAN_DEBUG
		printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
		return;
	}
	can_init_fifo( port );

	temp = can_get_reg( port, CAN_CR );
	can_put_reg( port, CAN_CR, temp|0x01 );
	udelay( 10000 );
	temp = inb( iohwbase[ port ] );
	outb( temp, iohwbase[ port ] );
	udelay(10000);
}

/* Check if the controller is resetted */

// ****************************************************************************
// Design Notes:  check if the port is resetted
//-----------------------------------------------------------------------------
static int can_is_resetted ( int port )
{
	int can_cr;
	unsigned long flags;
	if ( port < 0 || port >= MAX_DEVICE )
	{
#ifdef CAN_DEBUG
		printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
		return 1;
	}
	save_flags( flags );
	cli();
	can_cr = can_get_reg( port, CAN_CR );
	restore_flags( flags );
	return can_cr & CAN_RESET_REQUEST;
}

#define CAN_IRQ_ENA \
	( CAN_RECEIVE_INT_ENABLE)
//	| CAN_TRANSMIT_INT_ENABLE)
//	| CAN_ERROR_INT_ENABLE )
// ****************************************************************************
// Design Notes:  enable or disable interrupt
//-----------------------------------------------------------------------------
static void 
can_ena_irq ( 
	int port,
	int irq_enable )
{
	unsigned char temp;
	if ( port < 0 || port >= MAX_DEVICE )
	{
#ifdef CAN_DEBUG
		printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
		return;
	}
	if( can_state[ port ].protocol == CAN_PROTOCOL_20A )
	{
		temp = can_get_reg( port, CAN_CR );
		if ( irq_enable )
			//can_put_reg( port, CAN_CR, temp | CAN_IRQ_ENA );
			can_put_reg( port, CAN_CR, CAN_IRQ_ENA );
		else
			//can_put_reg( port, CAN_CR, temp&(~CAN_IRQ_ENA) );
			can_put_reg( port, CAN_CR, (~CAN_IRQ_ENA) );
	}
	else 
	{
		//CAN_PROTOCOL_20B
		if( irq_enable )
			can_put_reg( port, CAN_IER, can_state[port].interruptmask );
		else //!irq_enable
			can_put_reg( port, CAN_IER, 0 );
	}
	udelay( 5000 );
}


/* Init the CAN controller for a specific bit rate.
 * Enable TX and RX interrupts.
 * Push/Pull output for 82C250/251 driver circuit.
 */


// ****************************************************************************
// Design Notes:  setup the divice
//Parameters:
//   port: device port number to reset.
//   param: a struct for setup.
//Return Value:1 for success.
//-----------------------------------------------------------------------------
static int 
can_setup ( 
	int port,
	CAN_STRUCT *param )
{
	unsigned char bt0, bt1, temp;
	int i;
#ifdef CAN_DEBUG
	printk( "Enter can_setup, port = %d\n", port );
#endif

	if ( port < 0 || port >= findnum )
	{
#ifdef CAN_DEBUG
		printk( "in can_get_reg function the port=%d is error!\n", port );
#endif
		return -EINVAL;
	}  
	//set the port state
	can_state[ port ].protocol = param->protocol;
	can_state[ port ].interruptmask = param->interruptmask;
#ifdef CAN_DEBUG
	printk( "in function can_setup: set port%x protocol=%x  interruptmask=%x\n",
		port,can_state[ port ].protocol,param->interruptmask );
#endif

	switch( param->speed )
	{
	case CAN_10K:
		{
			bt0 = CAN_TIM0_10K;
			bt1 = CAN_TIM1_10K;
		}
		break;
	case CAN_20K:
		{
			bt0 = CAN_TIM0_20K;
			bt1 = CAN_TIM1_20K;
		}
		break;
	case CAN_40K:
		{
			bt0 = CAN_TIM0_40K;
			bt1 = CAN_TIM1_40K;
		}
		break;
	case CAN_50K:
		{
			bt0 = CAN_TIM0_50K;
			bt1 = CAN_TIM1_50K;
		}
		break;
	case CAN_100K:
		{
			bt0 = CAN_TIM0_100K;
			bt1 = CAN_TIM1_100K;
		}
		break;
	case CAN_125K:
		{
			bt0 = CAN_TIM0_125K;
			bt1 = CAN_TIM1_125K;
		}
		break;
	case CAN_500K:
		{
			bt0 = CAN_TIM0_500K;
			bt1 = CAN_TIM1_500K;
		}
		break;
  case CAN_800K:
		{
			bt0 = CAN_TIM0_800K;
			bt1 = CAN_TIM1_800K;
		}
		break;	
	case CAN_1000K:
		{
			bt0 = CAN_TIM0_1000K;
			bt1 = CAN_TIM1_1000K;
		}
		break;
	default:
		{
#ifdef CAN_DEBUG 
			printk( "Can_speed parameter is error!\n" );
#endif
		return -EINVAL;
		}
	}

	switch( param->protocol )
	{
	case CAN_PROTOCOL_20A:
		{

⌨️ 快捷键说明

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