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