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

📄 pcan_isa_linux.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
字号:
//****************************************************************************// Copyright (C) 2001-2007  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: Philipp Baer (philipp.baer@informatik.uni-ulm.de)//****************************************************************************//****************************************************************************//// all parts of the isa hardware for pcan-isa devices//// $Id: pcan_isa_linux.c $////****************************************************************************//****************************************************************************// DEFINES#define INIT_SAME_IRQ_LIST() init_same_irq_list(dev)//----------------------------------------------------------------------------// init shared interrupt linked listsstatic inline void init_same_irq_list(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: init_same_irq_list(%p)\n", DEVICE_NAME, dev);  INIT_LIST_HEAD(&dev->port.isa.anchor.same_irq_items); // init to no content  dev->port.isa.anchor.same_irq_count  = 0;             // no element in list  dev->port.isa.anchor.same_irq_active = 0;             // no active element  dev->port.isa.same.dev               = dev;           // points to me  dev->port.isa.my_anchor              = NULL;          // point to nowhere}//----------------------------------------------------------------------------// create lists of devices with the same irq - base for shared irq handlingvoid pcan_create_isa_shared_irq_lists(void){  struct pcandev *outer_dev;  struct pcandev *inner_dev;  struct list_head *outer_ptr, *inner_ptr;  DPRINTK(KERN_DEBUG "%s: pcan_create_isa_shared_irq_lists()\n", DEVICE_NAME);  // loop over all devices for a ISA port with same irq level and not myself  for (outer_ptr = pcan_drv.devices.next; outer_ptr != &pcan_drv.devices; outer_ptr = outer_ptr->next)  {    outer_dev = (struct pcandev *)outer_ptr;    // if it is a ISA device and still not associated    if ((outer_dev->wType == HW_ISA_SJA) && (outer_dev->port.isa.my_anchor == NULL))    {      outer_dev->port.isa.my_anchor = &outer_dev->port.isa.anchor; // then it is the root of a new list      outer_dev->port.isa.my_anchor->same_irq_count++;             // I'm the first and - maybe - the only one      list_add_tail(&outer_dev->port.isa.same.item, &outer_dev->port.isa.my_anchor->same_irq_items); // add to list      DPRINTK(KERN_DEBUG "%s: main Irq=%d, dev=%p, count=%d\n", DEVICE_NAME,                         outer_dev->port.isa.wIrq, outer_dev, outer_dev->port.isa.my_anchor->same_irq_count);      // now search for other devices with the same irq      for (inner_ptr = outer_ptr->next; inner_ptr != &pcan_drv.devices; inner_ptr = inner_ptr->next)      {        inner_dev = (struct pcandev *)inner_ptr;        // if it is a ISA device and the irq level is the same and it is still not associated        if ((inner_dev->wType == HW_ISA_SJA) && (inner_dev->port.isa.my_anchor == NULL) && (inner_dev->port.isa.wIrq == outer_dev->port.isa.wIrq))        {          inner_dev->port.isa.my_anchor = outer_dev->port.isa.my_anchor; // point and associate to the first with the same irq level          inner_dev->port.isa.my_anchor->same_irq_count++;               // no - there are more          list_add_tail(&inner_dev->port.isa.same.item, &inner_dev->port.isa.my_anchor->same_irq_items); // add to list          DPRINTK(KERN_DEBUG "%s: sub  Irq=%d, dev=%p, count=%d\n", DEVICE_NAME,                              inner_dev->port.isa.wIrq, inner_dev, inner_dev->port.isa.my_anchor->same_irq_count);        }      }    }  }}//----------------------------------------------------------------------------// only one irq-handler per irq level for ISA shared interruptsstatic irqreturn_t IRQHANDLER(pcan_isa_irqhandler, int irq, void *dev_id, struct pt_regs *regs){  // loop the list of irq-handlers for all devices with the same   // irq-level until at least all devices are one time idle.  SAME_IRQ_LIST *my_anchor = (SAME_IRQ_LIST *)dev_id;  struct list_head *ptr;  struct pcandev *dev;  int ret        = 0;  u16 loop_count = 0;  u16 stop_count = 100;  // DPRINTK(KERN_DEBUG "%s: pcan_isa_irqhandler(%p)\n", DEVICE_NAME, my_anchor);  // loop over all ISA devices with same irq level  for (ptr = my_anchor->same_irq_items.next; loop_count < my_anchor->same_irq_count; ptr = ptr->next)  {    if (ptr != &my_anchor->same_irq_items)    {      dev = ((SAME_IRQ_ITEM *)ptr)->dev;      // DPRINTK(KERN_DEBUG "%s: dev=%p\n", DEVICE_NAME, dev);      if (!IRQHANDLER(sja1000_base_irqhandler, irq, dev, regs))        loop_count++;      else      {        ret = 1;        loop_count = 0; // reset, I need at least my_anchor->same_irq_count loops without a pending request      }      if (!stop_count--)      {        printk(KERN_ERR "%s: Too much ISA interrupt load, processing halted!\n", DEVICE_NAME);        break;      }    }  }  return PCAN_IRQ_RETVAL(ret);}static int pcan_isa_req_irq(struct pcandev *dev){  int err;  DPRINTK(KERN_DEBUG "%s: pcan_isa_req_irq(%p)\n", DEVICE_NAME, dev);  if (dev->wInitStep == 3) // init has finished completly   {    if (!dev->port.isa.my_anchor->same_irq_active) // the first device    {      if ((err = request_irq(dev->port.isa.wIrq, pcan_isa_irqhandler, IRQF_DISABLED, "pcan", dev->port.isa.my_anchor)))        return err;    }    dev->port.isa.my_anchor->same_irq_active++;  // count all ISA devices with same irq    dev->wInitStep++;  }  return 0;}static void pcan_isa_free_irq(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pcan_isa_free_irq(%p)\n", DEVICE_NAME, dev);  if (dev->wInitStep == 4) // irq was installed  {    dev->port.isa.my_anchor->same_irq_active--;    if (!dev->port.isa.my_anchor->same_irq_active) // the last device      free_irq(dev->port.isa.wIrq, dev->port.isa.my_anchor);    dev->wInitStep--;  }}

⌨️ 快捷键说明

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