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

📄 pcan_usb_kernel.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 3 页
字号:
//****************************************************************************// Copyright (C) 2003-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://                Oliver Hartkopp   (oliver.hartkopp@volkswagen.de) socketCAN//                     //****************************************************************************//****************************************************************************//// pcan_usb-kernel.c - the inner parts for pcan-usb support//// $Id: pcan_usb_kernel.c 510 2007-05-29 13:07:10Z khitschler $////****************************************************************************//****************************************************************************// INCLUDES#include <src/pcan_common.h>#include <linux/sched.h>#include <src/pcan_main.h>#include <src/pcan_fifo.h>#include <src/pcan_usb_kernel.h>#include <asm/byteorder.h>       // because of little / big endian#ifdef NETDEV_SUPPORT#include <src/pcan_netdev.h>     // for hotplug pcan_netdev_register()#endif//****************************************************************************// DEFINES// bit masks for status/length field in a USB message#define STLN_WITH_TIMESTAMP 0x80#define STLN_INTERNAL_DATA  0x40#define STLN_EXTENDED_ID    0x20#define STLN_RTR            0x10#define STLN_DATA_LENGTH    0x0F         // mask for length of data bytes// Error-Flags for PCAN-USB#define XMT_BUFFER_FULL           0x01#define CAN_RECEIVE_QUEUE_OVERRUN 0x02#define BUS_LIGHT                 0x04#define BUS_HEAVY                 0x08#define BUS_OFF                   0x10#define QUEUE_RECEIVE_EMPTY       0x20#define QUEUE_OVERRUN             0x40#define QUEUE_XMT_FULL            0x80// timestamp calculation stuff#define FASTSCALE                            // use this for slow architectures without native 64 bit division support#define SCALED_MICROSECONDS_PER_TICK  44739  // error = 5,424e-4%#define SCALE_SHIFTER                    20  // unscale, shift runs faster than divide#define COMPARE_OFFSET                  128  // enhance wrap comparison tolerance caused by idle timestamps#define SCALE_MULTIPLIER               1024  // multiplier for direct calculation of timestamp#define SCALE_DIVISOR                 24000  // divisor for direct calculation of timestamp#define TICKS(msec) ((msec * HZ) / 1000)     // to calculate ticks from milliseconds#define COMMAND_TIMEOUT           1000       // msec timeout for control EP0 urb get settypedef struct                               // pcan-usb parameter get an set function{  u8  Function;  u8  Number;  u8  Param[14];} __attribute__ ((packed)) PCAN_USB_PARAM;//****************************************************************************// GLOBALS//****************************************************************************// LOCALS//****************************************************************************// CODE  //****************************************************************************// functions to handle time constructionstatic void pcan_reset_timestamp(struct pcandev *dev){  PCAN_USB_TIME *t = dev->port.usb.pUSBtime;  DPRINTK(KERN_DEBUG "%s: reset_timestamp()\n", DEVICE_NAME);  // reset time stamp information  t->ullCumulatedTicks    = 0;  t->ullOldCumulatedTicks = 0;  t->wLastTickValue       = 0;  t->ucLastTickValue      = 0;  t->wOldLastTickValue    = 0;  t->StartTime.tv_sec     = 0;  t->StartTime.tv_usec    = 0;    t->wStartTicks          = 0;}#if 0// TODO: take the timestamp from ticks * (42 + 2/3) usecs of PCAN-USBstatic inline void pcan_calcTimevalFromTicks(struct pcandev *dev, struct timeval *tv){  register PCAN_USB_TIME *t = dev->port.usb.pUSBtime;  u64 llx;  llx   = t->ullCumulatedTicks - t->wStartTicks;    // subtract initial offset    #ifdef FASTSCALE                                    llx  *= SCALED_MICROSECONDS_PER_TICK;               return  (u32)(llx >>= SCALE_SHIFTER);             // unscale, shift runs faster than divide  #else  llx  *= SCALE_MULTIPLIER;   return ((u32)(*(u64 *)&llx) / SCALE_DIVISOR);     // trick to circumvent missing __udivid3 entry message  #endif}static inline void pcan_getTimeStamp(struct pcandev *dev, struct timeval *tv){  ...}#endifstatic void pcan_updateTimeStampFromWord(struct pcandev *dev, u16 wTimeStamp, u8 ucStep){  register PCAN_USB_TIME *t = dev->port.usb.pUSBtime;  // DPRINTK(KERN_DEBUG "%s: updateTimeStampFromWord() Tim = %d, Last = %d, Cum = %lld\n", DEVICE_NAME, wTimeStamp, t->wLastTickValue, t->ullCumulatedTicks);  if ((!t->StartTime.tv_sec) && (!t->StartTime.tv_usec))  {    get_relative_time(NULL, &t->StartTime);    t->wStartTicks          = wTimeStamp;    t->wOldLastTickValue    = wTimeStamp;    t->ullCumulatedTicks    = wTimeStamp;    t->ullOldCumulatedTicks = wTimeStamp;  }  // correction for status timestamp in the same telegram which is more recent, restore old contents  if (ucStep)  {    t->ullCumulatedTicks = t->ullOldCumulatedTicks;    t->wLastTickValue    = t->wOldLastTickValue;  }      // store current values for old ...  t->ullOldCumulatedTicks = t->ullCumulatedTicks;  t->wOldLastTickValue    = t->wLastTickValue;      if (wTimeStamp < t->wLastTickValue)  // handle wrap, enhance tolerance    t->ullCumulatedTicks += 0x10000LL;  t->ullCumulatedTicks &= ~0xFFFFLL;   // mask in new 16 bit value - do not cumulate cause of error propagation  t->ullCumulatedTicks |= wTimeStamp;  t->wLastTickValue   = wTimeStamp;      // store for wrap recognition  t->ucLastTickValue  = (u8)(wTimeStamp & 0xff); // each update for 16 bit tick updates the 8 bit tick, too}static void pcan_updateTimeStampFromByte(struct pcandev *dev, u8 ucTimeStamp){  register PCAN_USB_TIME *t = dev->port.usb.pUSBtime;  // DPRINTK(KERN_DEBUG "%s: updateTimeStampFromByte() Tim = %d, Last = %d, Cum = %lld\n", DEVICE_NAME, ucTimeStamp, t->ucLastTickValue, t->ullCumulatedTicks);    if (ucTimeStamp < t->ucLastTickValue)  // handle wrap  {    t->ullCumulatedTicks += 0x100;    t->wLastTickValue    += 0x100;  }  t->ullCumulatedTicks &= ~0xFFLL;       // mask in new 8 bit value - do not cumulate cause of error propagation  t->ullCumulatedTicks |= ucTimeStamp;  t->wLastTickValue    &= ~0xFF;         // correction for word timestamp, too  t->wLastTickValue    |= ucTimeStamp;  t->ucLastTickValue    = ucTimeStamp;   // store for wrap recognition}//****************************************************************************// get and set parameters to or from device//#ifdef LINUX_26static void pcan_param_xmit_notify(struct urb *purb, struct pt_regs *regs)#elsestatic void pcan_param_xmit_notify(purb_t purb)#endif{  struct pcandev *dev = purb->context;  DPRINTK(KERN_DEBUG "%s: pcan_param_xmit_notify() = %d\n", DEVICE_NAME, purb->status);  // un-register outstanding urb  atomic_dec(&dev->port.usb.active_urbs);  atomic_set(&dev->port.usb.param_xmit_finished, 1);}static int pcan_hw_setcontrol_urb(struct pcandev *dev, u8 function, u8 number,                              u8 param0, u8 param1, u8 param2, u8 param3,  u8 param4,  u8 param5,  u8 param6,                              u8 param7, u8 param8, u8 param9, u8 param10, u8 param11, u8 param12, u8 param13){  PCAN_USB_PARAM myParameter;  int nResult = 0;  register purb_t pt;  // DPRINTK(KERN_DEBUG "%s: pcan_set_parameter()\n", DEVICE_NAME);  // don't do anything with non-existent hardware  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  myParameter.Function = function;  myParameter.Number   = number;  myParameter.Param[0]   = param0;  myParameter.Param[1]   = param1;  myParameter.Param[2]   = param2;  myParameter.Param[3]   = param3;  myParameter.Param[4]   = param4;  myParameter.Param[5]   = param5;  myParameter.Param[6]   = param6;  myParameter.Param[7]   = param7;  myParameter.Param[8]   = param8;  myParameter.Param[9]   = param9;  myParameter.Param[10]  = param10;  myParameter.Param[11]  = param11;  myParameter.Param[12]  = param12;  myParameter.Param[13]  = param13;  pt = dev->port.usb.param_urb;  FILL_BULK_URB(pt, dev->port.usb.usb_dev,                usb_sndbulkpipe(dev->port.usb.usb_dev, dev->port.usb.Endpoint[1].ucNumber),                &myParameter, sizeof(myParameter), pcan_param_xmit_notify, dev);  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)  pt->timeout = TICKS(COMMAND_TIMEOUT);  #endif    if (__usb_submit_urb(pt))  {    DPRINTK(KERN_ERR "%s: pcan_set_parameter() can't submit!\n",DEVICE_NAME);    nResult = pt->status;    goto fail;  }  else    atomic_inc(&dev->port.usb.active_urbs);  // wait until submit is finished, either normal or thru timeout  while (!atomic_read(&dev->port.usb.param_xmit_finished))    schedule();    // remove urb  nResult = pt->status;  fail:  atomic_set(&dev->port.usb.param_xmit_finished, 0);    return nResult;}     static int pcan_set_function(struct pcandev *dev, u8 function, u8 number){  DPRINTK(KERN_DEBUG "%s: pcan_set_function(%d, %d)\n", DEVICE_NAME, function, number);     return pcan_hw_setcontrol_urb(dev, function, number, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);}  // in opposition to WIN method this performs the complete write and read cycle!static int pcan_hw_getcontrol_urb(struct pcandev *dev, u8 function, u8 number,                              u8 *param0, u8 *param1, u8 *param2, u8 *param3,                              u8 *param4, u8 *param5, u8 *param6, u8 *param7){  PCAN_USB_PARAM myParameter;  int nResult = 0;  register purb_t pt;  USB_PORT *u = &dev->port.usb;    DPRINTK(KERN_DEBUG "%s: pcan_hw_getcontrol_urb(%d, %d)\n", DEVICE_NAME, function, number);   // don't do anything with non-existent hardware  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  // first write function and number to device  nResult = pcan_set_function(dev,  function, number);  // heuristic result - wait a little bit  mdelay(5);  if (!nResult)  {    u32 startTime;        pt = u->param_urb;    FILL_BULK_URB(pt, u->usb_dev,                  usb_rcvbulkpipe(u->usb_dev, u->Endpoint[0].ucNumber),                  &myParameter, sizeof(myParameter), pcan_param_xmit_notify, dev);      myParameter.Function = function;    myParameter.Number   = number;    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)    pt->timeout = TICKS(COMMAND_TIMEOUT);    #endif        if (__usb_submit_urb (pt))    {      printk(KERN_ERR "%s: pcan_get_parameter() can't submit!\n",DEVICE_NAME);      nResult = pt->status;      goto fail;    }    else      atomic_inc(&u->active_urbs);    startTime = get_mtime();    while (!atomic_read(&u->param_xmit_finished) && ((get_mtime() - startTime) < COMMAND_TIMEOUT))      schedule();    if (!atomic_read(&u->param_xmit_finished))    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)      usb_kill_urb(pt);    #else      usb_unlink_urb(pt); /* any better solution here for Kernel 2.4 ? */    #endif          if (!pt->status)    {      *param0 = myParameter.Param[0];       *param1 = myParameter.Param[1];      *param2 = myParameter.Param[2];      *param3 = myParameter.Param[3];      *param4 = myParameter.Param[4];      *param5 = myParameter.Param[5];      *param6 = myParameter.Param[6];      *param7 = myParameter.Param[7];    }    nResult = pt->status;  }  fail:  atomic_set(&u->param_xmit_finished, 0);    return nResult;}//****************************************************************************// specialized high level hardware access functions//static int pcan_hw_setBTR0BTR1(struct pcandev *dev, u16 wBTR0BTR1){  u8  dummy  = 0;  u8  param0 = (u8)(wBTR0BTR1 & 0xff);  u8  param1 = (u8)((wBTR0BTR1 >> 8) & 0xff);  DPRINTK(KERN_DEBUG "%s: pcan_hw_setBTR0BTR1(0x%04x)\n", DEVICE_NAME, wBTR0BTR1); 

⌨️ 快捷键说明

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