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

📄 pcan_dongle.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
字号:
//****************************************************************************// Copyright (C) 2001-2008 PEAK System-Technik GmbH//// linux@peak-system.com// www.peak-system.com//// 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., 675 Mass Ave, Cambridge, MA 02139, USA.//// Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)//// Major contributions by://                Edouard Tisserant (edouard.tisserant@lolitech.fr) XENOMAI//                Laurent Bessard   (laurent.bessard@lolitech.fr)   XENOMAI//                Oliver Hartkopp   (oliver.hartkopp@volkswagen.de) socketCAN//                     // Contributions: Marcel Offermans (marcel.offermans@luminis.nl)//                Philipp Baer (philipp.baer@informatik.uni-ulm.de)//****************************************************************************//***************************************************************************//// all parts to handle the interface specific parts of pcan-dongle//// $Id: pcan_dongle.c 533 2008-02-04 21:31:54Z khitschler $////****************************************************************************//****************************************************************************// INCLUDES#include <src/pcan_common.h>     // must always be the 1st include#include <linux/errno.h>#include <linux/ioport.h>#include <asm/io.h> #include <linux/sched.h>#include <linux/slab.h>#ifdef PARPORT_SUBSYSTEM#include <linux/parport.h>#endif#include <linux/delay.h>#include <linux/spinlock.h>#include <src/pcan_dongle.h>#include <src/pcan_sja1000.h>#include <src/pcan_filter.h>//****************************************************************************// DEFINES#define PCAN_DNG_SP_MINOR_BASE  16  // starting point of minors for SP devices#define PCAN_DNG_EPP_MINOR_BASE 24  // starting point of minors for EPP devices#define DNG_PORT_SIZE            4  // the address range of the dongle-port#define ECR_PORT_SIZE            1  // size of the associated ECR register#define DNG_DEFAULT_COUNT        4  // count of defaults for init//****************************************************************************// GLOBALS//****************************************************************************// LOCALSstatic u16 dng_ports[] = {0x378, 0x278, 0x3bc, 0x2bc};static u8  dng_irqs[]  = {7, 5, 7, 5};static u16 dng_devices = 0;        // the number of accepted dng_devicesstatic u16 epp_devices = 0;        // ... epp_devicesstatic u16 sp_devices  = 0;        // ... sp_devicesstatic unsigned char nibble_decode[32] ={  0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,  0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,  0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,  0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};//****************************************************************************// CODE#ifdef NO_RT  #include "pcan_dongle_linux.c"#else  #include "pcan_dongle_rt.c"#endif//----------------------------------------------------------------------------// enable and disable irqsstatic void _parport_disable_irq(struct pcandev *dev){  u16 _PC_ = (u16)dev->port.dng.dwPort + 2;  outb(inb(_PC_) & ~0x10, _PC_);}static void _parport_enable_irq(struct pcandev *dev){  u16 _PC_ = (u16)dev->port.dng.dwPort + 2;  outb(inb(_PC_) | 0x10, _PC_);}// functions for SP portstatic u8 pcan_dongle_sp_readreg(struct pcandev *dev, u8 port) // read a register{  u16 _PA_ = (u16)dev->port.dng.dwPort;  u16 _PB_ = _PA_ + 1;  u16 _PC_ = _PB_ + 1;  u8  b0, b1 ;  u8  irqEnable = inb(_PC_) & 0x10; // don't influence irqEnable   SPIN_LOCK_IRQSAVE();  outb((0x0B ^ 0x0D) | irqEnable, _PC_);  outb((port & 0x1F) | 0x80,      _PA_);  outb((0x0B ^ 0x0C) | irqEnable, _PC_);  b1=nibble_decode[inb(_PB_)>>3];  outb(0x40, _PA_);  b0=nibble_decode[inb(_PB_)>>3];  outb((0x0B ^ 0x0D) | irqEnable, _PC_);  SPIN_UNLOCK_IRQRESTORE();  return  (b1 << 4) | b0 ;}static void pcan_dongle_writereg(struct pcandev *dev, u8 port, u8 data) // write a register{  u16 _PA_ = (u16)dev->port.dng.dwPort;  u16 _PC_ = _PA_ + 2;  u8  irqEnable = inb(_PC_) & 0x10; // don't influence irqEnable  SPIN_LOCK_IRQSAVE();  outb((0x0B ^ 0x0D) | irqEnable, _PC_);  outb(port & 0x1F,               _PA_);  outb((0x0B ^ 0x0C) | irqEnable, _PC_);  outb(data,                      _PA_);  outb((0x0B ^ 0x0D) | irqEnable, _PC_);  SPIN_UNLOCK_IRQRESTORE();}// functions for EPP portstatic u8 pcan_dongle_epp_readreg(struct pcandev *dev, u8 port) // read a register{  u16 _PA_ = (u16)dev->port.dng.dwPort;  u16 _PC_ = _PA_ + 2;  u8  wert;  u8  irqEnable = inb(_PC_) & 0x10; // don't influence irqEnable  SPIN_LOCK_IRQSAVE();  outb((0x0B ^ 0x0F) | irqEnable, _PC_);  outb((port & 0x1F) | 0x80,      _PA_);  outb((0x0B ^ 0x2E) | irqEnable, _PC_);  wert = inb(_PA_);  outb((0x0B ^ 0x0F) | irqEnable, _PC_);  SPIN_UNLOCK_IRQRESTORE();  return wert;}static void pcan_dongle_free_irq(struct pcandev *dev){  if (dev->wInitStep == 4)  {    FREE_IRQ();    dev->wInitStep--;  }}// release and probe functionsstatic int pcan_dongle_cleanup(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pcan_dongle_cleanup()\n", DEVICE_NAME);  switch(dev->wInitStep)  {    case 4: pcan_dongle_free_irq(dev);    case 3: if (dev->wType == HW_DONGLE_SJA)               sp_devices--;             else               epp_devices--;             dng_devices = sp_devices + epp_devices;    case 2:           #ifndef PARPORT_SUBSYSTEM             if (dev->wType == HW_DONGLE_SJA_EPP)             release_region(dev->port.dng.wEcr, ECR_PORT_SIZE);           #endif    case 1:           #ifdef PARPORT_SUBSYSTEM             PARPORT_UNREGISTER_DEVICE();           #else             release_region(dev->port.dng.dwPort, DNG_PORT_SIZE);           #endif                case 0: pcan_delete_filter_chain(dev->filter);            dev->filter = NULL;            dev->wInitStep = 0;  }  return 0;}// to switch epp on or restore registerstatic void setECR(struct pcandev *dev){  u16 wEcr = dev->port.dng.wEcr;  dev->port.dng.ucOldECRContent = inb(wEcr);  outb((dev->port.dng.ucOldECRContent & 0x1F) | 0x20, wEcr);  if (dev->port.dng.ucOldECRContent == 0xff)    printk(KERN_DEBUG "%s: realy ECP mode configured?\n", DEVICE_NAME);}static void restoreECR(struct pcandev *dev){  u16 wEcr = dev->port.dng.wEcr;  outb(dev->port.dng.ucOldECRContent, wEcr);  DPRINTK(KERN_DEBUG "%s: restore ECR\n", DEVICE_NAME);}#ifdef PARPORT_SUBSYSTEMstatic int pcan_dongle_probe(struct pcandev *dev) // probe for type{  struct parport *p;    DPRINTK(KERN_DEBUG "%s: pcan_dongle_probe() - PARPORT_SUBSYSTEM\n", DEVICE_NAME);    // probe does not probe for the sja1000 device here - this is done at sja1000_open()  p = parport_find_base(dev->port.dng.dwPort);  if (!p)  {    DPRINTK(KERN_DEBUG "found no parport\n");    return -ENXIO;  }  else  {    // register my device at the parport in no realtime    PARPORT_REGISTER_DEVICE();  }  return 0;}#elsestatic int pcan_dongle_probe(struct pcandev *dev) // probe for type{  int result = 0;    DPRINTK(KERN_DEBUG "%s: pcan_dongle_probe()\n", DEVICE_NAME);    result = ___request_region(dev->port.dng.dwPort, DNG_PORT_SIZE, DEVICE_NAME);  if (!result)  {      dev->wInitStep = 1;    if (dev->wType == HW_DONGLE_SJA_EPP)    {      result = ___request_region(dev->port.dng.wEcr, ECR_PORT_SIZE, DEVICE_NAME);          if (!result)        dev->wInitStep = 2;    }  }    return result;}#endif // PARPORT_SUBSYSTEM// interface depended open and closestatic int pcan_dongle_open(struct pcandev *dev){  int result = 0;  u16 wPort;    DPRINTK(KERN_DEBUG "%s: pcan_dongle_open()\n", DEVICE_NAME);    PARPORT_CLAIM();    // save port state  if (!result)  {    wPort    = (u16)dev->port.dng.dwPort;        // save old port contents    dev->port.dng.ucOldDataContent     = inb(wPort);    dev->port.dng.ucOldControlContent  = inb(wPort + 2);        // switch to epp mode if possible    if (dev->wType == HW_DONGLE_SJA_EPP)      setECR(dev);       // enable irqs    #ifdef PARPORT_SUBSYSTEM    _parport_enable_irq(dev); // parport_enable_irq(dev->port.dng.pardev->port); not working since 2.4.18    #else    _parport_enable_irq(dev);    #endif  }      return result;}static int pcan_dongle_release(struct pcandev *dev){  u16 wPort = (u16)dev->port.dng.dwPort;  DPRINTK(KERN_DEBUG "%s: pcan_dongle_release()\n", DEVICE_NAME);    // disable irqs  #ifdef PARPORT_SUBSYSTEM  _parport_disable_irq(dev); // parport_disable_irq(dev->port.dng.pardev->port); not working since 2.4.18  #else  _parport_disable_irq(dev);  #endif  if (dev->wType == HW_DONGLE_SJA_EPP)    restoreECR(dev);      // restore port state  outb(dev->port.dng.ucOldDataContent, wPort);  outb(dev->port.dng.ucOldControlContent, wPort + 2);  PARPORT_RELEASE();  return 0;}static int  pcan_dongle_init(struct pcandev *dev, u32 dwPort, u16 wIrq, char *type){  int err;    DPRINTK(KERN_DEBUG "%s: pcan_dongle_init(), dng_devices = %d\n", DEVICE_NAME, dng_devices);    // init process wait queues  init_waitqueue_head(&dev->read_queue);  init_waitqueue_head(&dev->write_queue);    // set this before any instructions, fill struct pcandev, part 1   dev->wInitStep   = 0;    dev->cleanup     = pcan_dongle_cleanup;  dev->req_irq     = pcan_dongle_req_irq;  dev->free_irq    = pcan_dongle_free_irq;  dev->open        = pcan_dongle_open;  dev->release     = pcan_dongle_release;   dev->filter      = pcan_create_filter_chain();  spin_lock_init(&dev->port.dng.lock);  // fill struct pcandev, 1st check if a default is set  if (!dwPort)  {    // there's no default available    if (dng_devices >= DNG_DEFAULT_COUNT)      return -ENODEV;        dev->port.dng.dwPort = dng_ports[dng_devices];  }  else    dev->port.dng.dwPort = dwPort;    if (!wIrq)  {    if (dng_devices >= DNG_DEFAULT_COUNT)      return -ENODEV;        dev->port.dng.wIrq   = dng_irqs[dng_devices];      }  else    dev->port.dng.wIrq   = wIrq;        if (dev->wType == HW_DONGLE_SJA)  {    dev->nMinor        = PCAN_DNG_SP_MINOR_BASE + sp_devices;     dev->readreg       = pcan_dongle_sp_readreg;    dev->writereg      = pcan_dongle_writereg;    dev->port.dng.wEcr = 0; // set to anything  }  else  {    dev->nMinor        = PCAN_DNG_EPP_MINOR_BASE + epp_devices;      dev->readreg       = pcan_dongle_epp_readreg;    dev->writereg      = pcan_dongle_writereg;    dev->port.dng.wEcr = (u16)dev->port.dng.dwPort + 0x402;  }      // is the device really available?      if ((err = pcan_dongle_probe(dev)) < 0)  {    printk(KERN_ERR "%s: failed to claim port 0x%04x\n", DEVICE_NAME, dev->port.dng.dwPort);    return err;  }      dev->ucPhysicallyInstalled = 1;  if (dev->wType == HW_DONGLE_SJA)    sp_devices++;  else    epp_devices++;      dng_devices = sp_devices + epp_devices;    dev->wInitStep = 3;  printk(KERN_INFO "%s: %s-dongle device minor %d prepared (io=0x%04x,irq=%d)\n", DEVICE_NAME,                                dev->type, dev->nMinor, dev->port.dng.dwPort, dev->port.dng.wIrq);    return 0;}int pcan_create_dongle_devices(char *type, u32 io, u16 irq){  int result = 0;  struct pcandev *dev = NULL;    DPRINTK(KERN_DEBUG "%s: pcan_create_dongle_devices(%s, 0x%x, %d)\n", DEVICE_NAME, type, io, irq);    if ((dev = (struct pcandev *)kmalloc(sizeof(struct pcandev), GFP_KERNEL)) == NULL)    goto fail;  pcan_soft_init(dev, type, (!strncmp(type, "sp", 4)) ? HW_DONGLE_SJA : HW_DONGLE_SJA_EPP);    dev->device_open    = sja1000_open;  dev->device_write   = sja1000_write;  dev->device_release = sja1000_release;  #ifdef NETDEV_SUPPORT  dev->netdevice_write  = sja1000_write_frame;  #endif    result = pcan_dongle_init(dev, io, irq, type);    if (result)  {    dev->cleanup(dev);    kfree(dev);    goto fail;  }  else  {    list_add_tail(&dev->list, &pcan_drv.devices);  // add this device to the list            pcan_drv.wDeviceCount++;  }  fail:  if (result)    DPRINTK(KERN_DEBUG "%s: pcan_create_dongle_devices() failed!\n", DEVICE_NAME);  else    DPRINTK(KERN_DEBUG "%s: pcan_create_dongle_devices() OK!\n", DEVICE_NAME);      return result;}

⌨️ 快捷键说明

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