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

📄 pcan_netdev.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
字号:
//****************************************************************************// Copyright (C) 2006-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)// Contributions: Oliver Hartkopp (oliver.hartkopp@volkswagen.de)//****************************************************************************//****************************************************************************//// pcan_netdev.c - CAN network device support functions//// $Id: pcan_netdev.c 525 2007-10-17 13:06:25Z ohartkopp $//// For CAN netdevice / socketcan specific questions please check the// Mailing List <socketcan-users@lists.berlios.de>// Project homepage http://developer.berlios.de/projects/socketcan////****************************************************************************#include <src/pcan_common.h>#include <linux/sched.h>#include <linux/module.h>#include <linux/skbuff.h>#include <src/pcan_main.h>#include <src/pcan_fops.h>  /* pcan_open_path(), pcan_release_path() */#include <src/pcan_netdev.h>//----------------------------------------------------------------------------//----------------------------------------------------------------------------// Functions for AF_CAN netdevice adaptation//----------------------------------------------------------------------------//----------------------------------------------------------------------------//----------------------------------------------------------------------------// AF_CAN netdevice: open device//----------------------------------------------------------------------------static int pcan_netdev_open(struct net_device *dev){  struct can_priv *priv = netdev_priv(dev);  struct pcandev  *pdev = priv->pdev;  DPRINTK(KERN_DEBUG "%s: %s %s\n", DEVICE_NAME, __FUNCTION__, dev->name);  if (pcan_open_path(pdev))    return -ENODEV;  netif_start_queue(dev);  return 0;}//----------------------------------------------------------------------------// AF_CAN netdevice: close device//----------------------------------------------------------------------------static int pcan_netdev_close(struct net_device *dev){  struct can_priv *priv = netdev_priv(dev);  struct pcandev  *pdev = priv->pdev;  DPRINTK(KERN_DEBUG "%s: %s %s\n", DEVICE_NAME, __FUNCTION__, dev->name);  pcan_release_path(pdev);  netif_stop_queue(dev);  return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)//----------------------------------------------------------------------------// AF_CAN netdevice: get statistics for device//----------------------------------------------------------------------------static struct net_device_stats *pcan_netdev_get_stats(struct net_device *dev){  struct can_priv *priv = netdev_priv(dev);  /* TODO: read statistics from chip */  return &priv->stats;}#endif//----------------------------------------------------------------------------// AF_CAN netdevice: timeout handler for device//----------------------------------------------------------------------------static void pcan_netdev_tx_timeout(struct net_device *dev){  struct net_device_stats *stats = dev->get_stats(dev);  stats->tx_errors++;  netif_wake_queue(dev);}//----------------------------------------------------------------------------// AF_CAN netdevice: transmit handler for device//----------------------------------------------------------------------------static int pcan_netdev_tx(struct sk_buff *skb, struct net_device *dev){  struct can_priv *priv = netdev_priv(dev);  struct pcandev  *pdev = priv->pdev;  struct net_device_stats *stats = dev->get_stats(dev);  struct can_frame *cf = (struct can_frame*)skb->data;  DPRINTK(KERN_DEBUG "%s: %s %s\n", DEVICE_NAME, __FUNCTION__, dev->name);  netif_stop_queue(dev);  atomic_set(&pdev->DataSendReady, 0); /* for pcan chardevice */  pdev->netdevice_write(pdev, cf); /* ignore return value */  stats->tx_packets++;  stats->tx_bytes += cf->can_dlc;  dev->trans_start = jiffies;  dev_kfree_skb(skb);  return 0;}//----------------------------------------------------------------------------// AF_CAN netdevice: receive function (put can_frame to netdev queue)//----------------------------------------------------------------------------int pcan_netdev_rx(struct pcandev *dev, struct can_frame *cf, struct timeval *tv){  struct net_device *ndev = dev->netdev;  struct net_device_stats *stats = ndev->get_stats(ndev);  struct sk_buff *skb;  DPRINTK(KERN_DEBUG "%s: %s %s\n", DEVICE_NAME, __FUNCTION__, ndev->name);          skb = dev_alloc_skb(sizeof(struct can_frame));  if (skb == NULL)    return -ENOMEM;  skb->dev      = ndev;  skb->protocol = htons(ETH_P_CAN);  skb->pkt_type = PACKET_BROADCAST;  skb->ip_summed = CHECKSUM_UNNECESSARY;  #if 0  /*   * Currently the driver only supports timestamp setting at host arrival time.   * Therefore the netdev support can used the timestamp provided by netif_rx()   * which is set when there is no given timestamp (and when network timestamps   * are not disabled by default in the host). So we just use the mechanics   * like any other network device does ...   */  if (tv)    #ifdef LINUX_26    skb_set_timestamp(skb, tv);    #else    skb->stamp = *tv;    #endif  #endif  memcpy(skb_put(skb, sizeof(struct can_frame)), cf, sizeof(struct can_frame));    netif_rx(skb);  ndev->last_rx = jiffies;  stats->rx_packets++;  stats->rx_bytes += cf->can_dlc;  return 0;}//----------------------------------------------------------------------------// AF_CAN netdevice: initialize data structure//----------------------------------------------------------------------------void pcan_netdev_init(struct net_device *dev){  /* Fill in the the fields of the device structure with AF_CAN generic values */  if (!dev)    return;  dev->change_mtu           = NULL;  dev->set_mac_address      = NULL;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)  dev->hard_header          = NULL;  dev->rebuild_header       = NULL;  dev->hard_header_cache    = NULL;  dev->header_cache_update  = NULL;  dev->hard_header_parse    = NULL;#else  dev->header_ops           = NULL;#endif  dev->type             = ARPHRD_CAN;  dev->hard_header_len  = 0;  dev->mtu              = sizeof(struct can_frame);  dev->addr_len         = 0;  dev->tx_queue_len     = 10;  dev->flags            = IFF_NOARP;  dev->open             = pcan_netdev_open;  dev->stop             = pcan_netdev_close;  dev->hard_start_xmit  = pcan_netdev_tx;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)  dev->get_stats        = pcan_netdev_get_stats;#endif  dev->tx_timeout       = pcan_netdev_tx_timeout;  dev->watchdog_timeo   = TX_TIMEOUT;}//----------------------------------------------------------------------------// AF_CAN netdevice: try to reassign netdev name according to user needs//----------------------------------------------------------------------------void pcan_netdev_create_name(char *name, struct pcandev *pdev){  extern char *assign; /* module param: assignment for netdevice names */  if (!assign) /* auto assignment */    return;  if (!strncmp(assign, "peak", 4)) {    // assign=peak    snprintf(name, IFNAMSIZ-1, "can%d", pdev->nMinor); /* easy: /dev/pcanXX -> canXX */  } else {    // e.g. assign=pcan32:can1,pcan41:can2    int peaknum, netnum;    char *ptr = assign;    while (ptr < (assign + strlen(assign))) {      ptr = strchr(ptr, 'p'); /* search first 'p' from pcanXX */      if (!ptr)        return; /* no match => quit */      if (sscanf(ptr, "pcan%d:can%d", &peaknum, &netnum) != 2) {        printk(KERN_INFO "%s: bad parameter format in netdevice assignment.\n", DEVICE_NAME);        return; /* bad parameter format => quit */      }      if (peaknum == pdev->nMinor) {        snprintf(name, IFNAMSIZ-1, "can%d", netnum);        break; /* done */      }      ptr++; /* search for next 'p' */    }  }  if (name[0]) {    /* check wanted assigned 'name' against existing device names */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)    if (__dev_get_by_name(name)) {#else    if (__dev_get_by_name(&init_net, name)) {#endif      printk(KERN_INFO "%s: netdevice name %s to be assigned exists already.\n",             DEVICE_NAME, name);      name[0] = 0; /* mark for auto assignment */    }  }}//----------------------------------------------------------------------------// AF_CAN netdevice: register network device//----------------------------------------------------------------------------int pcan_netdev_register(struct pcandev *pdev){  struct net_device *ndev;  struct can_priv *priv;  char name[IFNAMSIZ] = {0};  pcan_netdev_create_name(name, pdev);  if (!name[0])    strncpy(name, CAN_NETDEV_NAME, IFNAMSIZ-1); /* use the default: autoassignment */#ifdef LINUX_26  ndev = alloc_netdev(sizeof(struct can_priv), name, pcan_netdev_init);  if (!ndev) {    printk(KERN_ERR "%s: out of memory\n", DEVICE_NAME);    return 1;  }  priv = netdev_priv(ndev);  if (register_netdev(ndev)) {    printk(KERN_INFO "%s: Failed registering netdevice\n", DEVICE_NAME);    free_netdev(ndev);    return 1;  }#else  ndev = (struct net_device*)kmalloc(sizeof(struct net_device), GFP_KERNEL);  if (!ndev) {    printk(KERN_ERR "%s: out of memory\n", DEVICE_NAME);    return 1;  }  memset(ndev, 0, sizeof(struct net_device));  priv = (struct can_priv*)kmalloc(sizeof(struct can_priv), GFP_KERNEL);  if (!priv) {    printk(KERN_ERR "%s: out of memory\n", DEVICE_NAME);    kfree(ndev);    return 1;  }  memset(priv, 0, sizeof(struct can_priv));  ndev->priv = priv;  /* fill net_device structure */  pcan_netdev_init(ndev);  strncpy(ndev->name, name, IFNAMSIZ-1); /* name the device */  SET_MODULE_OWNER(ndev);  if (register_netdev(ndev)) {    printk(KERN_INFO "%s: Failed registering netdevice\n", DEVICE_NAME);    kfree(priv);    kfree(ndev);    return 1;  }#endif  // Make references between pcan device and netdevice  priv->pdev   = pdev;  pdev->netdev = ndev;  printk(KERN_INFO "%s: registered netdevice %s for pcan %s hw (minor %d)\n",         DEVICE_NAME, ndev->name, pdev->type, pdev->nMinor);  return 0;}//----------------------------------------------------------------------------// AF_CAN netdevice: unregister network device//----------------------------------------------------------------------------int pcan_netdev_unregister(struct pcandev *pdev){  struct net_device *ndev = pdev->netdev;  struct can_priv *priv;  if (!ndev)    return 1;  DPRINTK(KERN_DEBUG "%s: %s %s\n", DEVICE_NAME, __FUNCTION__, ndev->name);  priv = netdev_priv(ndev);  unregister_netdev(ndev);#ifndef LINUX_26  if (priv)    kfree(priv);#endif    pdev->netdev = NULL; /* mark as unregistered */  return 0;}//----------------------------------------------------------------------------// End of functions for AF_CAN netdevice adaptation//---------------------------------------------------------------------------- 

⌨️ 快捷键说明

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