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

📄 can200.c

📁 This version 0.2 of driver for a simple CAN bus interface. 一个CAN 总线接口程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * can200.c * version 0.2 * * An interrupt driven can 82c200 handler for EPP mode parport. * Tested under Linux 2.2.14 on i386 PC architecture. * * * Copyright (c) 2000 Martin Homuth-Rosemann <homuth-rosemann@gmx.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. *  * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <linux/kernel.h>#include <linux/module.h>#if CONFIG_MODVERSIONS==1#define MODVERSIONS#include <linux/modversions.h>#endif#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 <asm/io.h>/* In 2.2.3 /usr/include/linux/version.h includes a * macro for this, but 2.0.35 doesn't - so I add it * here if necessary. */#ifndef KERNEL_VERSION#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))#endif/* Conditional compilation. LINUX_VERSION_CODE is * the code (as per KERNEL_VERSION) of this version. */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)#include <asm/uaccess.h>  /* for put_user */#endif#include "can200.h"#include "82c200.h"/* Init parameter, usage: * "insmod can200.o can200_io=0x278 can200_irq=5 can200_major = 60" */int can200_io     = LP_PORT;int can200_irq    = LP_IRQ;int can200_major  = CAN_MAJOR;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)MODULE_PARM( can200_io, "i" );MODULE_PARM( can200_irq, "i" );MODULE_PARM( can200_major, "i" );#endif/* Queues of waiting processes */static struct wait_queue *RdWaitQ = NULL;static struct wait_queue *WrWaitQ = NULL;/* 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;/* The length of a message from the can device */#define RD_FIFO_LEN (200*CAN_MSG_LEN)#define WR_FIFO_LEN (50*CAN_MSG_LEN)/* 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;static can_wr_fifo_t WrFifo;static void can_init_fifos( void ){        RdFifo.head = RdFifo.tail = RdFifo.size = 0;        RdFifo.status = FIFO_EMPTY;        WrFifo.head = WrFifo.tail = WrFifo.size = 0;        WrFifo.status = FIFO_EMPTY;}/*******************************************************************//*******************************************************************//*******************************************************************//* The lowest level access routines for the CAN controller chip. * This level handles the physical connection to out PC architecture. * (ISA card, parallel port in PS/2 or EPP mode, etc. (PCI?) * Default mode is the Enhanced Parallel Port*/#define LP_STAT (can200_io+1)#define LP_CTRL (can200_io+2)#ifdef USE_EPP_MODE/**************************//* Enhanced Parallel Port *//**************************/#define EPP_ADDR (can200_io+3)#define EPP_DATA (can200_io+4)static void can_put_reg( unsigned char reg, unsigned char value ){        outb( reg, EPP_ADDR );        outb( value, EPP_DATA );}static unsigned char can_get_reg( unsigned char reg ){        outb( reg, EPP_ADDR );        return inb( EPP_DATA );}static void can_reset( void ){        outb( LP_RESET_ON, LP_CTRL );        udelay( 5 );}static void can_ena_irq( int irq_enable ){        if ( irq_enable )                outb( LP_RESET_OFF | LP_IRQ_ENA, LP_CTRL );        else                outb( LP_RESET_OFF, LP_CTRL );}#endif#ifdef USE_PS2_MODE/*****************************************//* PS/2 mode bidirectional parallel port *//*****************************************/static unsigned char Port2;#define LP_DATA (can200_io)static void can_put_reg( unsigned char reg, unsigned char value ){        outb( Port2+1, LP_CTRL );    // R/W = 0 (write)        outb( reg, LP_DATA );        outb( Port2+8+1, LP_CTRL );  // /ADDRSTB = 0 (act).        outb( Port2+1, LP_CTRL );    // /ADDRSTB = 1 (inact.)        outb( value, LP_DATA );        outb( Port2+2+1, LP_CTRL );  // /DATASTB = 0 (act).        outb( Port2+1, LP_CTRL );    // /DATASTB = 1 (inact.)                outb( Port2, LP_CTRL );      // R/W, /DATSTB, /ADDRSTB = 1}static unsigned char can_get_reg( unsigned char reg ){        unsigned char value;                outb( Port2+1, LP_CTRL );    // R/W = 0 (write)        outb( reg, LP_DATA );        outb( Port2+8+1, LP_CTRL );  // /ADDRSTB = 0 (act).        outb( Port2+1, LP_CTRL );    // /ADDRSTB = 1 (inact.)        outb( Port2+32, LP_CTRL );   // R/W = 1 (read)        outb( Port2+32+2, LP_CTRL ); // /DATASTB = 0 (act).        value = inb( LP_DATA );        outb( Port2+32, LP_CTRL );   // /DATASTB = 1 (inact).        outb( Port2, LP_CTRL );      // R/W, /DATSTB, /ADDRSTB = 1        return value;}static void can_reset( void ){        //printk( "can_reset()\n" );        outb( Port2 = LP_RESET_ON, LP_CTRL );        udelay( 5 );}static void can_ena_irq( int irq_enable ){        //printk( "can_ena_int( %d )\n", irq_enable );        if ( irq_enable )                outb( Port2 = LP_RESET_OFF | LP_IRQ_ENA, LP_CTRL );        else                outb( Port2 = LP_RESET_OFF, LP_CTRL );}#endifstatic int stuck_interrupt( void ){        return inb( LP_STAT ) & 0x40;}/*******************************************************************//*******************************************************************//*******************************************************************//* Hardware detection and init function * Independent of PC interface type *//* check if there is a CAN controller connected and powered *//* TODO: check type (82C200 or SJA1000) */static int can_find_chip( void ){        can_reset();        /* Control Register, Reset Request bit */        if ( 0x21 != ( can_get_reg( CAN_CR ) & 0x21 ) )                return -ENXIO;        /* Status Register, TBS and TCS bits */        if ( 0x0c != can_get_reg( CAN_SR ) )                return -ENXIO;        /* Interrupt Register, unused bits 5..7 = 1 */        if ( 0xe0 != can_get_reg( CAN_IR ) )                return -ENXIO;        /* Clock Divider Register, divide by 12 (Motorola mode) */        if ( 0x05 != can_get_reg( CAN_CDR ) )                return -ENXIO;        can_ena_irq( 0 );        return SUCCESS;}/* Init the CAN controller for a specific bit rate. * Enable TX and RX interrupts. * Push/Pull output for 82C250/251 driver circuit. */#define CAN_IRQ_ENA \        ( CAN_RECEIVE_INT_ENABLE \        | CAN_TRANSMIT_INT_ENABLE \        | CAN_ERROR_INT_ENABLE )static int can_setup( int speed ){        static int btr0 = -1;        static int btr1 = -1;        int err;        if ( ( err = can_find_chip() ) < 0 )                return err;        switch ( speed ) {        case CAN_RESET:                if ( -1 == btr0 )                        return -1;                if ( -1 == btr1 )                        return -EINVAL;                break;        case CAN_10K:                btr0 = CAN_TIM0_10K;                btr1 = CAN_TIM1_10K;                break;        case CAN_20K:                btr0 = CAN_TIM0_20K;                btr1 = CAN_TIM1_20K;                break;        case CAN_40K:                btr0 = CAN_TIM0_40K;                btr1 = CAN_TIM1_40K;                break;        case CAN_50K:                btr0 = CAN_TIM0_50K;                btr1 = CAN_TIM1_50K;                break;        case CAN_100K:                btr0 = CAN_TIM0_100K;                btr1 = CAN_TIM1_100K;                break;        case CAN_125K:                btr0 = CAN_TIM0_125K;                btr1 = CAN_TIM1_125K;                break;        default:                return -EINVAL;        }        can_put_reg( CAN_CR, CAN_RESET_REQUEST );        can_put_reg( CAN_ACR, 0xFF ); // dummy

⌨️ 快捷键说明

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