首页 > 学院 > 开发设计 > 正文

can3--socketcan之mcp251x.c

2019-11-09 13:48:18
字体:
来源:转载
供稿:网友

转自http://www.cnblogs.com/-song/archive/2012/05/24/3331872.html

spi驱动结构见http://blog.csdn.net/songQQnew/article/details/7037583mcp251x.c几乎是抄袭dm9000的写作格式参考  

dm9000 driver 1

 理清一下驱动的线索******************************************************************在init函数中注册spi驱动mcp251x_can_driver

static int __init mcp251x_can_init(void)  {  DBG("init/n");      return spi_register_driver(&mcp251x_can_driver);  }  

在spi驱动mcp251x_can_driver的PRobe函数中分配net_device

static struct spi_driver mcp251x_can_driver = {      .driver = {          .name = DEVICE_NAME,//mcp2515          .bus = &spi_bus_type,          .owner = THIS_MODULE,      },          .id_table = mcp251x_id_table,      .probe = mcp251x_can_probe,//probe      .remove = __devexit_p(mcp251x_can_remove),      .suspend = mcp251x_can_suspend,      .resume = mcp251x_can_resume,  };    static int __devinit mcp251x_can_probe(struct spi_device *spi)  {        net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);      if (!net) {      ret = -ENOMEM;      goto error_alloc;      }      //注册net_device      register_candev(net);        //net_device的Operation结构体指定了操作函数集合       static const struct net_device_ops mcp251x_netdev_ops = {      .ndo_open = mcp251x_open,      .ndo_stop = mcp251x_stop,      .ndo_start_xmit = mcp251x_hard_start_xmit,      };  }  

应用层执行ifconfig can0 up时会调用到mcp251x_open在mcp251x_open函数中,

//打开设备  open_candev(net);  //申请中断  ret = request_irq(spi->irq, mcp251x_can_irq, /*IRQF_DISABLED |*/ IRQF_TRIGGER_LOW ,  DEVICE_NAME, priv);  //初始化工作队列,当做中断(接收)下半部,用于处理接收  INIT_WORK(&priv->irq_work,can_irq_work);  //初始化工作队列,用于处理发送  INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);  

应用层执行write socket时会调用到mcp251x_hard_start_xmit,在 mcp251x_hard_start_xmit函数中,

//停止协议栈向驱动发送数据(在发送数据的时候需要停止协议栈发来新的需要发送出去的数据),发送完成后会重新启用  netif_stop_queue(net);  //启动发送工作队列,将数据(skb)发送出去  priv->tx_skb = skb;  queue_work(priv->wq, &priv->tx_work);  

具体看一下这个发送工作队列函数

static void mcp251x_tx_work_handler(struct work_struct *ws)  {      struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,                           tx_work);      struct spi_device *spi = priv->spi;      struct net_device *net = priv->net;      struct can_frame *frame;    //  printk("mcp251x_tx_work_handler/n");        mutex_lock(&priv->mcp_lock);      if (priv->tx_skb) {          if (priv->can.state == CAN_STATE_BUS_OFF) {              mcp251x_clean(net);          } else {              frame = (struct can_frame *)priv->tx_skb->data;                if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)                  frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;              mcp251x_hw_tx(spi, frame, 0);              priv->tx_len = 1 + frame->can_dlc;              can_put_echo_skb(priv->tx_skb, net, 0);              priv->tx_skb = NULL;          }      }      mutex_unlock(&priv->mcp_lock);  }  

怎么接收呢?当然是在中断处理函数中接收,有中断产生时,会启用一个负责接受的工作队列,即中断下半部,去接收。并将接收到的数据保存,以供应用层使用read socket等来读取。

static irqreturn_t mcp251x_can_irq(int irq, void *dev_id)  {  DBG("zhongduan :mcp251x_can_irq/n");         struct mcp251x_priv *priv = dev_id;          disable_irq_nosync(irq);//禁止中断,工作队列函数中接收完成时会重新使能中断         if (!work_pending(&priv->irq_work))          queue_work(priv->wq, &priv->irq_work);//调用工作队列函数         return IRQ_HANDLED;  }  

接收工作队列函数

void can_irq_work(struct work_struct *ws)  {    DBG("zhongduan bottom: can_irq_work/n");       struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,                           irq_work);       struct spi_device *spi = priv->spi;       struct net_device *net = priv->net;        mutex_lock(&priv->mcp_lock);          //mcp251x_write_reg(spi, CANINTE, (intset & (~ ( CANINTE_TX2IE) )));      while (!priv->force_quit) {          enum can_state new_state;          u8 intf, eflag;                  u8 clear_intf = 0;          int can_id = 0, data1 = 0;                             mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);                  DBG("intf=%x/n",intf);//一般返回1,表示rxb0里有数据。                  //mcp251x_write_bits(spi, CANINTF, intf, 0x00);                    /* mask out flags we don't care about */          intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR ;//| CANINTF_MERRF;                    if (intf & CANINTF_TX) {//如果是发送完成中断                net->stats.tx_packets++;              net->stats.tx_bytes += priv->tx_len - 1;              if (priv->tx_len) {                  can_get_echo_skb(net, 0);                  priv->tx_len = 0;              }              netif_wake_queue(net);//重新开启          }                      /* receive buffer 1 */          if (intf & CANINTF_RX1IF) {//如果是从mcp251x的buffer 1接收到数据的中断                mcp251x_hw_rx(spi, 1);//接收              /* the MCP2515 does this automatically */              if (mcp251x_is_2510(spi))                  clear_intf |= CANINTF_RX1IF;//清除mcp251x里的中断标志          }                    /* receive buffer 0 */          if (intf & CANINTF_RX0IF) {//如果是从mcp251x的buffer 0接收到数据的中断                mcp251x_hw_rx(spi, 0);//接收mcp2515的rxb0里的数据,见下              /*              * Free one buffer ASAP              * (The MCP2515 does this automatically.)              */              if (mcp251x_is_2510(spi))                  mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);//清除mcp251x里的中断标志          }                 /* any error or tx interrupt we need to clear? */          if (intf & (CANINTF_ERR | CANINTF_TX))              clear_intf |= intf & (CANINTF_ERR | CANINTF_TX);          if (clear_intf)              mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);            if (eflag)              mcp251x_write_bits(spi, EFLG, eflag, 0x00);                               /* Update can state */          if (eflag & EFLG_TXBO) {              new_state = CAN_STATE_BUS_OFF;              can_id |= CAN_ERR_BUSOFF;          } else if (eflag & EFLG_TXEP) {              new_state = CAN_STATE_ERROR_PASSIVE;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_TX_PASSIVE;          } else if (eflag & EFLG_RXEP) {              new_state = CAN_STATE_ERROR_PASSIVE;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_RX_PASSIVE;          } else if (eflag & EFLG_TXWAR) {              new_state = CAN_STATE_ERROR_WARNING;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_TX_WARNING;          } else if (eflag & EFLG_RXWAR) {              new_state = CAN_STATE_ERROR_WARNING;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_RX_WARNING;          } else {              new_state = CAN_STATE_ERROR_ACTIVE;          }            /* Update can state statistics */          switch (priv->can.state) {          case CAN_STATE_ERROR_ACTIVE:              if (new_state >= CAN_STATE_ERROR_WARNING &&                  new_state <= CAN_STATE_BUS_OFF)                  priv->can.can_stats.error_warning++;          case CAN_STATE_ERROR_WARNING:   /* fallthrough */              if (new_state >= CAN_STATE_ERROR_PASSIVE &&                  new_state <= CAN_STATE_BUS_OFF)                  priv->can.can_stats.error_passive++;              break;          default:              break;          }          priv->can.state = new_state;            if (intf & CANINTF_ERRIF) {              /* Handle overflow counters */              if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {                  if (eflag & EFLG_RX0OVR) {                      net->stats.rx_over_errors++;                      net->stats.rx_errors++;                  }                  if (eflag & EFLG_RX1OVR) {                      net->stats.rx_over_errors++;                      net->stats.rx_errors++;                  }                  can_id |= CAN_ERR_CRTL;                  data1 |= CAN_ERR_CRTL_RX_OVERFLOW;              }              mcp251x_error_skb(net, can_id, data1);          }              if (priv->can.state == CAN_STATE_BUS_OFF) {              if (priv->can.restart_ms == 0) {                  priv->force_quit = 1;                  can_bus_off(net);                  mcp251x_hw_sleep(spi);                  break;              }          }                    if (intf == 0)              break;              }          //mcp251x_write_reg(spi, CANINTE, intset);      mutex_unlock(&priv->mcp_lock);                     enable_irq(spi->irq);//重新使能中断          //s3c_gpio_cfgpin(S3C64XX_GPL(8), S3C_GPIO_SFN(3));     }  

附mcp251x.c源码

/*  * CAN bus driver for Microchip 251x CAN Controller with SPI Interface  *  * MCP2510 support and bug fixes by Christian Pellegrin  * <chripell@evolware.org>  *  * Copyright 2009 Christian Pellegrin EVOL S.r.l.  *  * Copyright 2007 Raymarine UK, Ltd. All Rights Reserved.  * Written under contract by:  *   Chris Elston, Katalix Systems, Ltd.  *  * Based on Microchip MCP251x CAN controller driver written by  * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.  *  * Based on CAN bus driver for the CCAN controller written by  * - Sascha Hauer, Marc Kleine-Budde, Pengutronix  * - Simon Kallweit, intefo AG  * Copyright 2007  *  * This program is free software; you can redistribute it and/or modify  * it under the terms of the version 2 of the GNU General Public License  * as published by the Free Software Foundation  *  * 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  *  *  *  * Your platform definition file should specify something like:  *  * static struct mcp251x_platform_data mcp251x_info = {  *         .oscillator_frequency = 8000000,  *         .board_specific_setup = &mcp251x_setup,  *         .power_enable = mcp251x_power_enable,  *         .transceiver_enable = NULL,  * };  *  * static struct spi_board_info spi_board_info[] = {  *         {  *                 .modalias = "mcp2510",  *            // or "mcp2515" depending on your controller  *                 .platform_data = &mcp251x_info,  *                 .irq = IRQ_EINT13,  *                 .max_speed_hz = 2*1000*1000,  *                 .chip_select = 2,  *         },  * };  *  * Please see mcp251x.h for a description of the fields in  * struct mcp251x_platform_data.  *  */      #define DEBUG    #ifdef DEBUG      #define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__)      #else      #define DBG(...)      #endif        #include <linux/can/core.h>  #include <linux/can/dev.h>  #include <linux/can/platform/mcp251x.h>  #include <linux/completion.h>  #include <linux/delay.h>  #include <linux/device.h>  #include <linux/dma-mapping.h>  #include <linux/freezer.h>  #include <linux/interrupt.h>  #include <linux/io.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/netdevice.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/spi/spi.h>  #include <linux/uaccess.h>      #include <linux/gpio.h>  #include <plat/gpio-cfg.h>    /* SPI interface instruction set */  #define INSTRUCTION_WRITE    0x02  #define INSTRUCTION_READ    0x03  #define INSTRUCTION_BIT_MODIFY    0x05  #define INSTRUCTION_LOAD_TXB(n)    (0x40 + 2 * (n))  #define INSTRUCTION_READ_RXB(n)    (((n) == 0) ? 0x90 : 0x94)  #define INSTRUCTION_RESET    0xC0    /* MPC251x registers */  #define CANSTAT          0x0e  #define CANCTRL          0x0f  #  define CANCTRL_REQOP_MASK        0xe0  #  define CANCTRL_REQOP_CONF        0x80  #  define CANCTRL_REQOP_LISTEN_ONLY 0x60  #  define CANCTRL_REQOP_LOOPBACK    0x40  #  define CANCTRL_REQOP_SLEEP        0x20  #  define CANCTRL_REQOP_NORMAL        0x00  #  define CANCTRL_OSM            0x08  #  define CANCTRL_ABAT            0x10  #define TEC          0x1c  #define REC          0x1d  #define CNF1          0x2a  #  define CNF1_SJW_SHIFT   6  #define CNF2          0x29  #  define CNF2_BTLMODE       0x80  #  define CNF2_SAM         0x40  #  define CNF2_PS1_SHIFT   3  #define CNF3          0x28  #  define CNF3_SOF       0x08  #  define CNF3_WAKFIL       0x04  #  define CNF3_PHSEG2_MASK 0x07  #define CANINTE          0x2b  #  define CANINTE_MERRE 0x80  #  define CANINTE_WAKIE 0x40  #  define CANINTE_ERRIE 0x20  #  define CANINTE_TX2IE 0x10  #  define CANINTE_TX1IE 0x08  #  define CANINTE_TX0IE 0x04  #  define CANINTE_RX1IE 0x02  #  define CANINTE_RX0IE 0x01  #define CANINTF          0x2c  #  define CANINTF_MERRF 0x80  #  define CANINTF_WAKIF 0x40  #  define CANINTF_ERRIF 0x20  #  define CANINTF_TX2IF 0x10  #  define CANINTF_TX1IF 0x08  #  define CANINTF_TX0IF 0x04  #  define CANINTF_RX1IF 0x02  #  define CANINTF_RX0IF 0x01  #  define CANINTF_RX (CANINTF_RX0IF | CANINTF_RX1IF)  #  define CANINTF_TX (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)  #  define CANINTF_ERR (CANINTF_ERRIF)  #define EFLG          0x2d  #  define EFLG_EWARN    0x01  #  define EFLG_RXWAR    0x02  #  define EFLG_TXWAR    0x04  #  define EFLG_RXEP    0x08  #  define EFLG_TXEP    0x10  #  define EFLG_TXBO    0x20  #  define EFLG_RX0OVR    0x40  #  define EFLG_RX1OVR    0x80  #define TXBCTRL(n)  (((n) * 0x10) + 0x30 + TXBCTRL_OFF)  #  define TXBCTRL_ABTF    0x40  #  define TXBCTRL_MLOA    0x20  #  define TXBCTRL_TXERR 0x10  #  define TXBCTRL_TXREQ 0x08  #define TXBSIDH(n)  (((n) * 0x10) + 0x30 + TXBSIDH_OFF)  #  define SIDH_SHIFT    3  #define TXBSIDL(n)  (((n) * 0x10) + 0x30 + TXBSIDL_OFF)  #  define SIDL_SID_MASK    7  #  define SIDL_SID_SHIFT   5  #  define SIDL_EXIDE_SHIFT 3  #  define SIDL_EID_SHIFT   16  #  define SIDL_EID_MASK    3  #define TXBEID8(n)  (((n) * 0x10) + 0x30 + TXBEID8_OFF)  #define TXBEID0(n)  (((n) * 0x10) + 0x30 + TXBEID0_OFF)  #define TXBDLC(n)   (((n) * 0x10) + 0x30 + TXBDLC_OFF)  #  define DLC_RTR_SHIFT    6  #define TXBCTRL_OFF 0  #define TXBSIDH_OFF 1  #define TXBSIDL_OFF 2  #define TXBEID8_OFF 3  #define TXBEID0_OFF 4  #define TXBDLC_OFF  5  #define TXBDAT_OFF  6  #define RXBCTRL(n)  (((n) * 0x10) + 0x60 + RXBCTRL_OFF)  #  define RXBCTRL_BUKT    0x04  #  define RXBCTRL_RXM0    0x20  #  define RXBCTRL_RXM1    0x40  #define RXBSIDH(n)  (((n) * 0x10) + 0x60 + RXBSIDH_OFF)  #  define RXBSIDH_SHIFT 3  #define RXBSIDL(n)  (((n) * 0x10) + 0x60 + RXBSIDL_OFF)  #  define RXBSIDL_IDE   0x08  #  define RXBSIDL_SRR   0x10  #  define RXBSIDL_EID   3  #  define RXBSIDL_SHIFT 5  #define RXBEID8(n)  (((n) * 0x10) + 0x60 + RXBEID8_OFF)  #define RXBEID0(n)  (((n) * 0x10) + 0x60 + RXBEID0_OFF)  #define RXBDLC(n)   (((n) * 0x10) + 0x60 + RXBDLC_OFF)  #  define RXBDLC_LEN_MASK  0x0f  #  define RXBDLC_RTR       0x40  #define RXBCTRL_OFF 0  #define RXBSIDH_OFF 1  #define RXBSIDL_OFF 2  #define RXBEID8_OFF 3  #define RXBEID0_OFF 4  #define RXBDLC_OFF  5  #define RXBDAT_OFF  6  #define RXFSIDH(n) ((n) * 4)  #define RXFSIDL(n) ((n) * 4 + 1)  #define RXFEID8(n) ((n) * 4 + 2)  #define RXFEID0(n) ((n) * 4 + 3)  #define RXMSIDH(n) ((n) * 4 + 0x20)  #define RXMSIDL(n) ((n) * 4 + 0x21)  #define RXMEID8(n) ((n) * 4 + 0x22)  #define RXMEID0(n) ((n) * 4 + 0x23)    #define GET_BYTE(val, byte)            /      (((val) >> ((byte) * 8)) & 0xff)  #define SET_BYTE(val, byte)            /      (((val) & 0xff) << ((byte) * 8))    /*  * Buffer size required for the largest SPI transfer (i.e., reading a  * frame)  */  #define CAN_FRAME_MAX_DATA_LEN    8  #define SPI_TRANSFER_BUF_LEN    (6 + CAN_FRAME_MAX_DATA_LEN)  #define CAN_FRAME_MAX_BITS    128    #define TX_ECHO_SKB_MAX    1    #define DEVICE_NAME "mcp2515"        //static struct timer_list check_timer;  void can_irq_work(struct work_struct *ws);  //static struct work_struct can_work;    static int intset;//中断设置      static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */  module_param(mcp251x_enable_dma, int, S_IRUGO);  MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");    static struct can_bittiming_const mcp251x_bittiming_const = {      .name = DEVICE_NAME,      .tseg1_min = 3,      .tseg1_max = 16,      .tseg2_min = 2,      .tseg2_max = 8,      .sjw_max = 4,      .brp_min = 1,      .brp_max = 64,      .brp_inc = 1,  };    enum mcp251x_model {      CAN_MCP251X_MCP2510    = 0x2510,      CAN_MCP251X_MCP2515    = 0x2515,  };    struct mcp251x_priv {      struct can_priv       can;      struct net_device *net;      struct spi_device *spi;      enum mcp251x_model model;        struct mutex mcp_lock; /* SPI device lock */        u8 *spi_tx_buf;      u8 *spi_rx_buf;      dma_addr_t spi_tx_dma;      dma_addr_t spi_rx_dma;        struct sk_buff *tx_skb;      int tx_len;        struct workqueue_struct *wq;      struct work_struct tx_work;      struct work_struct restart_work;            struct work_struct irq_work;        int force_quit;      int after_suspend;  #define AFTER_SUSPEND_UP 1  #define AFTER_SUSPEND_DOWN 2  #define AFTER_SUSPEND_POWER 4  #define AFTER_SUSPEND_RESTART 8      int restart_tx;  };    #define MCP251X_IS(_model) /  static inline int mcp251x_is_##_model(struct spi_device *spi) /  { /      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); /      return priv->model == CAN_MCP251X_MCP##_model; /  }    MCP251X_IS(2510);  MCP251X_IS(2515);    static void mcp251x_clean(struct net_device *net)  {      struct mcp251x_priv *priv = netdev_priv(net);    //    DBG("mcp251x_clean/n");        if (priv->tx_skb || priv->tx_len)          net->stats.tx_errors++;      if (priv->tx_skb)          dev_kfree_skb(priv->tx_skb);      if (priv->tx_len)          can_free_echo_skb(priv->net, 0);      priv->tx_skb = NULL;      priv->tx_len = 0;  }    /*  * Note about handling of error return of mcp251x_spi_trans: accessing  * registers via SPI is not really different conceptually than using  * normal I/O assembler instructions, although it's much more  * complicated from a practical POV. So it's not advisable to always  * check the return value of this function. Imagine that every  * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)  * error();", it would be a great mess (well there are some situation  * when exception handling C++ like could be useful after all). So we  * just check that transfers are OK at the beginning of our  * conversation with the chip and to avoid doing really nasty things  * (like injecting bogus packets in the network stack).  */  static int mcp251x_spi_trans(struct spi_device *spi, int len)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);      struct spi_transfer t = {          .tx_buf = priv->spi_tx_buf,          .rx_buf = priv->spi_rx_buf,          .len = len,          .cs_change = 0,      };      struct spi_message m;      int ret;    //    DBG("mcp251x_spi_trans/n");        spi_message_init(&m);        if (mcp251x_enable_dma) {          t.tx_dma = priv->spi_tx_dma;          t.rx_dma = priv->spi_rx_dma;          m.is_dma_mapped = 1;      }        spi_message_add_tail(&t, &m);        ret = spi_sync(spi, &m);          //ret= spi_async (spi,&m);      if (ret)          dev_err(&spi->dev, "spi transfer failed: ret = %d/n", ret);               int i=0;    DBG("打印spi直接发送的数据/n");  for( i=0;i<len;i++)  {  DBG("priv->spi_tx_buf[%d]=%x/n",i,priv->spi_tx_buf[i]);  }    DBG("打印spi直接收到的数据/n");  for( i=0;i<len;i++)  {  DBG("priv->spi_rx_buf[%d]=%x/n",i,priv->spi_rx_buf[i]);  }      return ret;  }    static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);        u8 val = 0;     //INSTRUCTION_READ=3  //根据mcp2515手册p64,使用spi接口读取寄存器的步骤是发送 命令03+地址  //接收到的寄存器数据在spi_rx_buf[2]      priv->spi_tx_buf[0] = INSTRUCTION_READ;      priv->spi_tx_buf[1] = reg;        mcp251x_spi_trans(spi, 3);      val = priv->spi_rx_buf[2];        return val;  }    static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,          uint8_t *v1, uint8_t *v2)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);        priv->spi_tx_buf[0] = INSTRUCTION_READ;      priv->spi_tx_buf[1] = reg;        mcp251x_spi_trans(spi, 4);  ////接收到的寄存器数据在spi_rx_buf[2],spi_rx_buf[3]      *v1 = priv->spi_rx_buf[2];      *v2 = priv->spi_rx_buf[3];  }    static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)  {            struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);     //INSTRUCTION_WRITE=2  //根据mcp2515手册p64,使用spi接口写寄存器的步骤是发送 命令02+地址+值        priv->spi_tx_buf[0] = INSTRUCTION_WRITE;      priv->spi_tx_buf[1] = reg;      priv->spi_tx_buf[2] = val;        mcp251x_spi_trans(spi, 3);  }    static void mcp251x_write_bits(struct spi_device *spi, u8 reg,                     u8 mask, uint8_t val)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);    //INSTRUCTION_BIT_MODIFY=5  //位修改指令,对可执行位操作的寄存器有效      priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;      priv->spi_tx_buf[1] = reg;      priv->spi_tx_buf[2] = mask;      priv->spi_tx_buf[3] = val;        mcp251x_spi_trans(spi, 4);  }    static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,                  int len, int tx_buf_idx)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);  //如果是2510,还需要指定使用那个发送缓冲区发送数据  //      if (mcp251x_is_2510(spi)) {          int i;          for (i = 1; i < TXBDAT_OFF + len; i++)              mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,                        buf[i]);      } else {          memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);          mcp251x_spi_trans(spi, TXBDAT_OFF + len);      }  }    static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,                int tx_buf_idx)  {      u32 sid, eid, exide, rtr;      u8 buf[SPI_TRANSFER_BUF_LEN];      exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */  DBG("打印是否扩展帧/n");      if (exide)          {          sid = (frame->can_id & CAN_EFF_MASK) >> 18;          DBG("是扩展帧/n");          }      else          {          sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */          DBG("是标准帧/n");          }      eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */      rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */  //INSTRUCTION_LOAD_TXB(0)=0x40,即装载tx0缓冲器      buf[TXBCTRL_OFF] = INSTRUCTION_LOAD_TXB(tx_buf_idx);      buf[TXBSIDH_OFF] = sid >> SIDH_SHIFT;      buf[TXBSIDL_OFF] = ((sid & SIDL_SID_MASK) << SIDL_SID_SHIFT) |          (exide << SIDL_EXIDE_SHIFT) |          ((eid >> SIDL_EID_SHIFT) & SIDL_EID_MASK);      buf[TXBEID8_OFF] = GET_BYTE(eid, 1);      buf[TXBEID0_OFF] = GET_BYTE(eid, 0);      buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc;      memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);  int i;  DBG("打印送给spi的数据/n");  for(i=0;i<SPI_TRANSFER_BUF_LEN;i++)  {  DBG("buf[%d]=%x/n",i,buf[i]);  }      mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);//装载到tx0缓冲器      mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);//请求发送tx0  }    static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,                  int buf_idx)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);    //        DBG("mcp251x_hw_rx_frame/n");  DBG("打印是否是mcp2515/n");      if (mcp251x_is_2510(spi)) {  DBG("是mcp2510/n");          int i, len;          for (i = 1; i < RXBDAT_OFF; i++)              buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);            len = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);          for (; i < (RXBDAT_OFF + len); i++)              buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);      } else {  DBG("是mcp2515/n");  //INSTRUCTION_READ_RXB(0)=90,即读取rx0缓冲器          priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);  /*SPI_TRANSFER_BUF_LEN=14, 即spi的发送和接收缓冲区都设为14 因为mcp2515共返回14个字节,假如是读rxbuf0,则 RXBOCTRL RXB0SIDH RXB0SIDL RXB0EID8 RXB0EID0 RXB0DLC RXB0D0 ... RXB0D7 */          mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);          memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);      }  }    static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);      struct sk_buff *skb;      struct can_frame *frame;      u8 buf[SPI_TRANSFER_BUF_LEN];    //    DBG("mcp251x_hw_rx/n");        skb = alloc_can_skb(priv->net, &frame);      if (!skb) {          dev_err(&spi->dev, "cannot allocate RX skb/n");          priv->net->stats.rx_dropped++;          return;      }        mcp251x_hw_rx_frame(spi, buf, buf_idx);// 接收数据    DBG("打印从spi接收到buf里的数据/n");      DBG(" buf_idx=%d/n",buf_idx);      int i;      for(i=0;i<SPI_TRANSFER_BUF_LEN;i++)      {      DBG(" buf[%d]=%x/n",i,buf[i]);      }    DBG("打印是否是扩展帧/n");      if (buf[RXBSIDL_OFF] & RXBSIDL_IDE) {  //buf[RXBSIDL_OFF]即buf[2]即寄存器RXBnSIDL的第4位表示是否是扩展帧  DBG("是扩展帧/n");          /* Extended ID format */          frame->can_id = CAN_EFF_FLAG;          frame->can_id |=              /* Extended ID part */              SET_BYTE(buf[RXBSIDL_OFF] & RXBSIDL_EID, 2) |              SET_BYTE(buf[RXBEID8_OFF], 1) |              SET_BYTE(buf[RXBEID0_OFF], 0) |              /* Standard ID part */              (((buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |                (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT)) << 18);          /* Remote transmission request */          if (buf[RXBDLC_OFF] & RXBDLC_RTR)              frame->can_id |= CAN_RTR_FLAG;      } else {  DBG("是标准帧/n");          /* Standard ID format */    //RXBSIDH的全8位和RXBSIDL的高3位即11位共同组成标准帧的标识符,详见mcp2515手册,  //所以理论上一条can总线最多可分辨2048个设备(扩展帧也是11位标识符)  //如果  //buf[1]=寄存器RXBSIDH=0x24=0010 0100,<<3=0010 0100 000  //buf[2]=寄存器RXBSIDL=0x60=0110 0000,>>5=011  //加上之后=001 0010 0011=0x123          frame->can_id =              (buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |              (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT);            if (buf[RXBSIDL_OFF] & RXBSIDL_SRR)              frame->can_id |= CAN_RTR_FLAG;        }      /* Data length */  //buf[3]=寄存器RXBEID8,标准帧不使用  //buf[4]=寄存器RXBEID0,标准帧不使用  //buf[5]=寄存器RXBDLC=数据段长度      frame->can_dlc = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);  //buf[6]-buf[13]=8个数据寄存器RXB0D0-RXB0D7      memcpy(frame->data, buf + RXBDAT_OFF, frame->can_dlc);  DBG("打印can_frame的字段/n");  DBG(" frame->can_id=0x%x/n", frame->can_id);  char *p=(char*)&(frame->can_id);  for(i=0;i<4;i++)  {  DBG(" p=%x/n",*p);  p++;  }    DBG(" frame->can_dlc=%d/n", frame->can_dlc);    for(i=0;i<8;i++)  {  DBG(" frame->data[%d]=%x/n",i,frame->data[i]);  }        priv->net->stats.rx_packets++;      priv->net->stats.rx_bytes += frame->can_dlc;  DBG("打印skb里的数据/n");  for(i=0;i<20;i++)  {  DBG("skb->data[%d]=%x/n",i,skb->data[i]);  }      netif_rx_ni(skb);  }    static void mcp251x_hw_sleep(struct spi_device *spi)  {  //    DBG("mcp251x_hw_sleep/n");      mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);  }    static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,                         struct net_device *net)  {      struct mcp251x_priv *priv = netdev_priv(net);      struct spi_device *spi = priv->spi;  DBG("从应用层收到发送命令/n");      if (priv->tx_skb || priv->tx_len) {          dev_warn(&spi->dev, "hard_xmit called while tx busy/n");          return NETDEV_TX_BUSY;      }        if (can_dropped_invalid_skb(net, skb))          return NETDEV_TX_OK;        netif_stop_queue(net);      priv->tx_skb = skb;  DBG("要发送的数据是skb/n");  DBG("启动发送队列/n");      queue_work(priv->wq, &priv->tx_work);        return NETDEV_TX_OK;  }    static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)  {      struct mcp251x_priv *priv = netdev_priv(net);             //        DBG("mcp251x_do_set_mode/n");        switch (mode) {      case CAN_MODE_START:          mcp251x_clean(net);          /* We have to delay work since SPI I/O may sleep */          priv->can.state = CAN_STATE_ERROR_ACTIVE;          priv->restart_tx = 1;          if (priv->can.restart_ms == 0)              priv->after_suspend = AFTER_SUSPEND_RESTART;          queue_work(priv->wq, &priv->restart_work);          break;      default:          return -EOPNOTSUPP;      }        return 0;  }    static int mcp251x_set_normal_mode(struct spi_device *spi)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);      unsigned long timeout;    //     DBG("mcp251x_set_normal_mode/n");        /* Enable interrupts */          intset=CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE | //CANINTF_MERRF |                CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE;      mcp251x_write_reg(spi, CANINTE,intset);          if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {          /* Put device into loopback mode */          mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);      } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {          /* Put device into listen-only mode */          mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LISTEN_ONLY);      } else {          /* Put device into normal mode */          mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);            /* Wait for the device to enter normal mode */          timeout = jiffies + HZ;          while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) {              schedule();              if (time_after(jiffies, timeout)) {                  dev_err(&spi->dev, "MCP251x didn't"                      " enter in normal mode/n");                  return -EBUSY;              }          }      }      priv->can.state = CAN_STATE_ERROR_ACTIVE;      return 0;  }    static int mcp251x_do_set_bittiming(struct net_device *net)  {      struct mcp251x_priv *priv = netdev_priv(net);      struct can_bittiming *bt = &priv->can.bittiming;      struct spi_device *spi = priv->spi;    //    DBG("mcp251x_do_set_bittiming/n");        mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << CNF1_SJW_SHIFT) |                (bt->brp - 1));      mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE |                (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ?                 CNF2_SAM : 0) |                ((bt->phase_seg1 - 1) << CNF2_PS1_SHIFT) |                (bt->prop_seg - 1));      mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,                 (bt->phase_seg2 - 1));      dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x/n",           mcp251x_read_reg(spi, CNF1),           mcp251x_read_reg(spi, CNF2),           mcp251x_read_reg(spi, CNF3));        return 0;  }    static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,               struct spi_device *spi)  {      mcp251x_do_set_bittiming(net);    //    DBG("mcp251x_setup/n");        mcp251x_write_reg(spi, RXBCTRL(0),                RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);      mcp251x_write_reg(spi, RXBCTRL(1),                RXBCTRL_RXM0 | RXBCTRL_RXM1);      return 0;  }    static int mcp251x_hw_reset(struct spi_device *spi)  {      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);      int ret;      unsigned long timeout;    //    DBG("mcp251x_hw_reset/n");        priv->spi_tx_buf[0] = INSTRUCTION_RESET;      ret = spi_write(spi, priv->spi_tx_buf, 1);      if (ret) {          dev_err(&spi->dev, "reset failed: ret = %d/n", ret);          return -EIO;      }        /* Wait for reset to finish */      timeout = jiffies + HZ;      mdelay(10);      while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)             != CANCTRL_REQOP_CONF) {          schedule();          if (time_after(jiffies, timeout)) {              dev_err(&spi->dev, "MCP251x didn't"                  " enter in conf mode after reset/n");              return -EBUSY;          }      }      return 0;  }    static int mcp251x_hw_probe(struct spi_device *spi)  {      int st1, st2;    //    DBG("mcp251x_hw_probe/n");        mcp251x_hw_reset(spi);        /*      * Please note that these are "magic values" based on after      * reset defaults taken from data sheet which allows us to see      * if we really have a chip on the bus (we avoid common all      * zeroes or all ones situations)      */      st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;      st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;        dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x/n", st1, st2);        /* Check for power up default values */      return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;  }    static void mcp251x_open_clean(struct net_device *net)  {      struct mcp251x_priv *priv = netdev_priv(net);      struct spi_device *spi = priv->spi;      struct mcp251x_platform_data *pdata = spi->dev.platform_data;            DBG("mcp251x_open_clean/n");        free_irq(spi->irq, priv);      mcp251x_hw_sleep(spi);      if (pdata->transceiver_enable)          pdata->transceiver_enable(0);      close_candev(net);  }    static int mcp251x_stop(struct net_device *net)  {      struct mcp251x_priv *priv = netdev_priv(net);      struct spi_device *spi = priv->spi;      struct mcp251x_platform_data *pdata = spi->dev.platform_data;         DBG("mcp251x_stop/n");        close_candev(net);        priv->force_quit = 1;              free_irq(spi->irq, priv);      destroy_workqueue(priv->wq);      priv->wq = NULL;    //        del_timer(&check_timer);  //删除定时器        mutex_lock(&priv->mcp_lock);        /* Disable and clear pending interrupts */      mcp251x_write_reg(spi, CANINTE, 0x00);      mcp251x_write_reg(spi, CANINTF, 0x00);        mcp251x_write_reg(spi, TXBCTRL(0), 0);      mcp251x_clean(net);        mcp251x_hw_sleep(spi);        if (pdata->transceiver_enable)          pdata->transceiver_enable(0);        priv->can.state = CAN_STATE_STOPPED;        mutex_unlock(&priv->mcp_lock);        return 0;  }    static void mcp251x_error_skb(struct net_device *net, int can_id, int data1)  {      struct sk_buff *skb;      struct can_frame *frame;         DBG("mcp251x_error_skb/n");        skb = alloc_can_err_skb(net, &frame);      if (skb) {          frame->can_id |= can_id;          frame->data[1] = data1;          netif_rx_ni(skb);      } else {          dev_err(&net->dev,              "cannot allocate error skb/n");      }  }    static void mcp251x_tx_work_handler(struct work_struct *ws)  {  DBG("进入发送队列/n");      struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,                           tx_work);      struct spi_device *spi = priv->spi;      struct net_device *net = priv->net;      struct can_frame *frame;        mutex_lock(&priv->mcp_lock);      if (priv->tx_skb) {          if (priv->can.state == CAN_STATE_BUS_OFF) {              mcp251x_clean(net);          } else {  int i;  DBG("打印skb里的数据/n");  for(i=0;i<20;i++)  {  DBG("priv->tx_skb->data[%d]=%x/n",i,priv->tx_skb->data[i]);  }  //将skb里的数据给can_frame以便组织发送              frame = (struct can_frame *)priv->tx_skb->data;  DBG("打印can_frame的字段/n");  DBG(" frame->can_id=0x%x/n", frame->can_id);  char *p=(char*)&(frame->can_id);  for(i=0;i<4;i++)  {  DBG(" p=%x/n",*p);  p++;  }  DBG(" frame->can_dlc=%d/n", frame->can_dlc);  for(i=0;i<8;i++)  {  DBG(" frame->data[%d]=%x/n",i,frame->data[i]);  }              if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)                  frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;  //发送              mcp251x_hw_tx(spi, frame, 0);                priv->tx_len = 1 + frame->can_dlc;              can_put_echo_skb(priv->tx_skb, net, 0);              priv->tx_skb = NULL;          }      }      mutex_unlock(&priv->mcp_lock);  }    static void mcp251x_restart_work_handler(struct work_struct *ws)  {      struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,                           restart_work);      struct spi_device *spi = priv->spi;      struct net_device *net = priv->net;        DBG("mcp251x_restart_work_handler/n");        mutex_lock(&priv->mcp_lock);      if (priv->after_suspend) {          mdelay(10);          mcp251x_hw_reset(spi);          mcp251x_setup(net, priv, spi);          if (priv->after_suspend & AFTER_SUSPEND_RESTART) {              mcp251x_set_normal_mode(spi);          } else if (priv->after_suspend & AFTER_SUSPEND_UP) {              netif_device_attach(net);              mcp251x_clean(net);              mcp251x_set_normal_mode(spi);              netif_wake_queue(net);          } else {              mcp251x_hw_sleep(spi);          }          priv->after_suspend = 0;          priv->force_quit = 0;      }        if (priv->restart_tx) {          priv->restart_tx = 0;          mcp251x_write_reg(spi, TXBCTRL(0), 0);          mcp251x_clean(net);          netif_wake_queue(net);          mcp251x_error_skb(net, CAN_ERR_RESTARTED, 0);      }      mutex_unlock(&priv->mcp_lock);  }      /*static void check_timer_callback(unsigned long arg) {     //DBG("timer clean CANINTF %X/n",arg);     //int pin=gpio_get_value(S3C64XX_GPL(8));  //   int pin=gpio_get_value(S3C64XX_GPN(5));      int pin=gpio_get_value(S3C64XX_GPL(8));  //    DBG("timer pin=%d /n",pin);      if(pin==0)     { //        struct mcp251x_priv *priv=(struct mcp251x_priv *)arg; //        schedule_work(&(priv->irq_work));          DBG("timer schedule work/n");     }     mod_timer(&check_timer,jiffies+8);        //修改定时器  }*/      static irqreturn_t mcp251x_can_irq(int irq, void *dev_id)  {  DBG("有中断产生/n");         struct mcp251x_priv *priv = dev_id;  //       struct spi_device *spi = priv->spi;        // int pin=gpio_get_value(S3C64XX_GPL(8));        // DBG("pin=%d /n",pin);     //DBG("before disable_irq_nosync(irq);/n");          disable_irq_nosync(irq);      //disable_irq(irq);  //DBG("after disable_irq_nosync(irq);/n");         //s3c_gpio_cfgpin(S3C64XX_GPL(8), S3C_GPIO_INPUT);  //关中断,为什么disable_irq死机         //while(S3C_GPIO_INPUT!=s3c_gpio_getcfg(S3C64XX_GPL(8)));         //schedule_work(&(priv->irq_work));            if (!work_pending(&priv->irq_work))          queue_work(priv->wq, &priv->irq_work);              //enable_irq(irq);         return IRQ_HANDLED;  }  /* static irqreturn_t mcp251x_can_irq(int irq, void *dev_id) { DBG("mcp251x_can_irq/n");        struct mcp251x_priv *priv = dev_id; //       struct spi_device *spi = priv->spi;       // int pin=gpio_get_value(S3C64XX_GPL(8));       // DBG("pin=%d /n",pin);            //disable_irq_nosync(irq);        s3c_gpio_cfgpin(S3C64XX_GPL(8), S3C_GPIO_INPUT);  //关中断,为什么disable_irq死机        while(S3C_GPIO_INPUT!=s3c_gpio_getcfg(S3C64XX_GPL(8)));        //schedule_work(&(priv->irq_work));          if (!work_pending(&priv->irq_work))         queue_work(priv->wq, &priv->irq_work);               return IRQ_HANDLED; } */        void can_irq_work(struct work_struct *ws)  {    DBG("进入中断下半部/n");       struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,                           irq_work);       struct spi_device *spi = priv->spi;       struct net_device *net = priv->net;        mutex_lock(&priv->mcp_lock);          //mcp251x_write_reg(spi, CANINTE, (intset & (~ ( CANINTE_TX2IE) )));      while (!priv->force_quit) {          enum can_state new_state;          u8 intf, eflag;                  u8 clear_intf = 0;          int can_id = 0, data1 = 0;                             mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);  //读取中断标志寄存器,用于判断是什么中断                  DBG("中断标志=0x%x/n",intf);                  //mcp251x_write_bits(spi, CANINTF, intf, 0x00);                    /* mask out flags we don't care about */          intf &= CANINTF_RX | CANINTF_TX | CANINTF_ERR ;//| CANINTF_MERRF;                    if (intf & CANINTF_TX) {  DBG("是发送完成中断: /n");              net->stats.tx_packets++;              net->stats.tx_bytes += priv->tx_len - 1;              if (priv->tx_len) {                  can_get_echo_skb(net, 0);                  priv->tx_len = 0;              }              netif_wake_queue(net);          }                      /* receive buffer 1 */          if (intf & CANINTF_RX1IF) {  DBG("是接收到数据中断: /n");  DBG("receive buffer1有数据/n");              mcp251x_hw_rx(spi, 1);              /* the MCP2515 does this automatically */              if (mcp251x_is_2510(spi))                  clear_intf |= CANINTF_RX1IF;          }                    /* receive buffer 0 */          if (intf & CANINTF_RX0IF) {  DBG("是接收到数据中断: /n");  DBG("receive buffer0有数据/n");              mcp251x_hw_rx(spi, 0);              /*              * Free one buffer ASAP              * (The MCP2515 does this automatically.)              */              if (mcp251x_is_2510(spi))                  mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);          }                 /* any error or tx interrupt we need to clear? */          if (intf & (CANINTF_ERR | CANINTF_TX))              clear_intf |= intf & (CANINTF_ERR | CANINTF_TX);          if (clear_intf)              mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);            if (eflag)              mcp251x_write_bits(spi, EFLG, eflag, 0x00);                               /* Update can state */          if (eflag & EFLG_TXBO) {              new_state = CAN_STATE_BUS_OFF;              can_id |= CAN_ERR_BUSOFF;          } else if (eflag & EFLG_TXEP) {              new_state = CAN_STATE_ERROR_PASSIVE;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_TX_PASSIVE;          } else if (eflag & EFLG_RXEP) {              new_state = CAN_STATE_ERROR_PASSIVE;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_RX_PASSIVE;          } else if (eflag & EFLG_TXWAR) {              new_state = CAN_STATE_ERROR_WARNING;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_TX_WARNING;          } else if (eflag & EFLG_RXWAR) {              new_state = CAN_STATE_ERROR_WARNING;              can_id |= CAN_ERR_CRTL;              data1 |= CAN_ERR_CRTL_RX_WARNING;          } else {              new_state = CAN_STATE_ERROR_ACTIVE;          }            /* Update can state statistics */          switch (priv->can.state) {          case CAN_STATE_ERROR_ACTIVE:              if (new_state >= CAN_STATE_ERROR_WARNING &&                  new_state <= CAN_STATE_BUS_OFF)                  priv->can.can_stats.error_warning++;          case CAN_STATE_ERROR_WARNING:    /* fallthrough */              if (new_state >= CAN_STATE_ERROR_PASSIVE &&                  new_state <= CAN_STATE_BUS_OFF)                  priv->can.can_stats.error_passive++;              break;          default:              break;          }          priv->can.state = new_state;            if (intf & CANINTF_ERRIF) {              /* Handle overflow counters */              if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {                  if (eflag & EFLG_RX0OVR) {                      net->stats.rx_over_errors++;                      net->stats.rx_errors++;                  }                  if (eflag & EFLG_RX1OVR) {                      net->stats.rx_over_errors++;                      net->stats.rx_errors++;                  }                  can_id |= CAN_ERR_CRTL;                  data1 |= CAN_ERR_CRTL_RX_OVERFLOW;              }              mcp251x_error_skb(net, can_id, data1);          }              if (priv->can.state == CAN_STATE_BUS_OFF) {              if (priv->can.restart_ms == 0) {                  priv->force_quit = 1;                  can_bus_off(net);                  mcp251x_hw_sleep(spi);                  break;              }          }                    if (intf == 0)              break;              }          //mcp251x_write_reg(spi, CANINTE, intset);      mutex_unlock(&priv->mcp_lock);            enable_irq(spi->irq);          //s3c_gpio_cfgpin(S3C64XX_GPL(8), S3C_GPIO_SFN(3));    //开中断   }          static int mcp251x_open(struct net_device *net)  {      struct mcp251x_priv *priv = netdev_priv(net);      struct spi_device *spi = priv->spi;      struct mcp251x_platform_data *pdata = spi->dev.platform_data;      int ret;     //       DBG("mcp251x_open/n");  DBG("mcp251x_open");      ret = open_candev(net);      if (ret) {          dev_err(&spi->dev, "unable to set initial baudrate!/n");          return ret;      }        mutex_lock(&priv->mcp_lock);      if (pdata->transceiver_enable)          pdata->transceiver_enable(1);        priv->force_quit = 0;      priv->tx_skb = NULL;      priv->tx_len = 0;    /*    ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,           pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING, //IRQF_TRIGGER_LOW,  //            DEVICE_NAME, priv);*/        ret = request_irq(spi->irq, mcp251x_can_irq,                //IRQF_TRIGGER_FALLING,                            /*IRQF_DISABLED |*/ IRQF_TRIGGER_LOW , //note by song                DEVICE_NAME, priv);        INIT_WORK(&priv->irq_work,can_irq_work);          if (ret) {          dev_err(&spi->dev, "failed to acquire irq %d/n", spi->irq);          if (pdata->transceiver_enable)              pdata->transceiver_enable(0);          close_candev(net);          goto open_unlock;      }    //    init_timer(&check_timer);   //初始化定时器  //        check_timer.expires=jiffies+HZ;  //        check_timer.function=&check_timer_callback;  //        check_timer.data=(long)priv;          //add_timer(&check_timer);        //添加定时器*/        priv->wq = create_freezable_workqueue("mcp251x_wq");          //priv->wq = create_freezeable_workqueue("mcp251x_wq");        INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);      INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);        ret = mcp251x_hw_reset(spi);      if (ret) {          mcp251x_open_clean(net);          goto open_unlock;      }      ret = mcp251x_setup(net, priv, spi);      if (ret) {          mcp251x_open_clean(net);          goto open_unlock;      }      ret = mcp251x_set_normal_mode(spi);      if (ret) {          mcp251x_open_clean(net);          goto open_unlock;      }      netif_wake_queue(net);    open_unlock:      mutex_unlock(&priv->mcp_lock);      return ret;  }    static const struct net_device_ops mcp251x_netdev_ops = {      .ndo_open = mcp251x_open,      .ndo_stop = mcp251x_stop,      .ndo_start_xmit = mcp251x_hard_start_xmit,  };    static int __devinit mcp251x_can_probe(struct spi_device *spi)  {      struct net_device *net;      struct mcp251x_priv *priv;      struct mcp251x_platform_data *pdata = spi->dev.platform_data;      int ret = -ENODEV;        DBG("@@@@@@@@@@@@@@@@@@@@/n");      DBG("mcp251x_can_probe /n");      DBG("@@@@@@@@@@@@@@@@@@@@/n");        if (!pdata)          /* Platform data is required for osc freq */          goto error_out;        /* Allocate can/net device */      net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);      if (!net) {          ret = -ENOMEM;          goto error_alloc;      }        net->netdev_ops = &mcp251x_netdev_ops;      net->flags |= IFF_ECHO;        priv = netdev_priv(net);      priv->can.bittiming_const = &mcp251x_bittiming_const;      priv->can.do_set_mode = mcp251x_do_set_mode;      priv->can.clock.freq = pdata->oscillator_frequency / 2;      priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |          CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;      priv->model = spi_get_device_id(spi)->driver_data;      priv->net = net;      dev_set_drvdata(&spi->dev, priv);        priv->spi = spi;      mutex_init(&priv->mcp_lock);            /* If requested, allocate DMA buffers */      if (mcp251x_enable_dma) {          spi->dev.coherent_dma_mask = ~0;          /*          * Minimum coherent DMA allocation is PAGE_SIZE, so allocate          * that much and share it between Tx and Rx DMA buffers.          */          priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,                                PAGE_SIZE,                                &priv->spi_tx_dma,                                GFP_DMA);            if (priv->spi_tx_buf) {              priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +                            (PAGE_SIZE / 2));              priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +                              (PAGE_SIZE / 2));          } else {              /* Fall back to non-DMA */              mcp251x_enable_dma = 0;          }      }        /* Allocate non-DMA buffers */      if (!mcp251x_enable_dma) {          priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);          if (!priv->spi_tx_buf) {              ret = -ENOMEM;              goto error_tx_buf;          }          priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);          if (!priv->spi_rx_buf) {              ret = -ENOMEM;              goto error_rx_buf;          }      }        if (pdata->power_enable)          pdata->power_enable(1);        /* Call out to platform specific setup */      if (pdata->board_specific_setup)          pdata->board_specific_setup(spi);        SET_NETDEV_DEV(net, &spi->dev);        /* Configure the SPI bus */      spi->mode = SPI_MODE_0;      spi->bits_per_Word = 8;      spi_setup(spi);        /* Here is OK to not lock the MCP, no one knows about it yet */      if (!mcp251x_hw_probe(spi)) {          dev_info(&spi->dev, "Probe failed/n");          goto error_probe;      }      mcp251x_hw_sleep(spi);        if (pdata->transceiver_enable)          pdata->transceiver_enable(0);        ret = register_candev(net);      DBG("@@@@@@@@@@@@@@@@@@@@/n");      DBG("register_candev ret = %d/n",ret);      DBG("@@@@@@@@@@@@@@@@@@@@/n");      if (!ret) {          dev_info(&spi->dev, "probed/n");          return ret;      }  error_probe:      if (!mcp251x_enable_dma)          kfree(priv->spi_rx_buf);  error_rx_buf:      if (!mcp251x_enable_dma)          kfree(priv->spi_tx_buf);  error_tx_buf:      free_candev(net);      if (mcp251x_enable_dma)          dma_free_coherent(&spi->dev, PAGE_SIZE,                    priv->spi_tx_buf, priv->spi_tx_dma);  error_alloc:      if (pdata->power_enable)          pdata->power_enable(0);      dev_err(&spi->dev, "probe failed/n");  error_out:      return ret;  }    static int __devexit mcp251x_can_remove(struct spi_device *spi)  {      struct mcp251x_platform_data *pdata = spi->dev.platform_data;      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);      struct net_device *net = priv->net;        DBG("mcp251x_can_remove/n");        unregister_candev(net);      free_candev(net);        if (mcp251x_enable_dma) {          dma_free_coherent(&spi->dev, PAGE_SIZE,                    priv->spi_tx_buf, priv->spi_tx_dma);      } else {          kfree(priv->spi_tx_buf);          kfree(priv->spi_rx_buf);      }        if (pdata->power_enable)          pdata->power_enable(0);        return 0;  }    #ifdef CONFIG_PM  static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)  {      struct mcp251x_platform_data *pdata = spi->dev.platform_data;      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);      struct net_device *net = priv->net;        DBG("mcp251x_can_suspend/n");        priv->force_quit = 1;      disable_irq(spi->irq);      /*      * Note: at this point neither IST nor workqueues are running.      * open/stop cannot be called anyway so locking is not needed      */      if (netif_running(net)) {          netif_device_detach(net);            mcp251x_hw_sleep(spi);          if (pdata->transceiver_enable)              pdata->transceiver_enable(0);          priv->after_suspend = AFTER_SUSPEND_UP;      } else {          priv->after_suspend = AFTER_SUSPEND_DOWN;      }        if (pdata->power_enable) {          pdata->power_enable(0);          priv->after_suspend |= AFTER_SUSPEND_POWER;      }        return 0;  }    static int mcp251x_can_resume(struct spi_device *spi)  {          DBG("mcp251x_can_resume/n");      struct mcp251x_platform_data *pdata = spi->dev.platform_data;      struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);        if (priv->after_suspend & AFTER_SUSPEND_POWER) {          pdata->power_enable(1);          queue_work(priv->wq, &priv->restart_work);      } else {          if (priv->after_suspend & AFTER_SUSPEND_UP) {              if (pdata->transceiver_enable)                  pdata->transceiver_enable(1);              queue_work(priv->wq, &priv->restart_work);          } else {              priv->after_suspend = 0;          }      }      priv->force_quit = 0;      enable_irq(spi->irq);      return 0;  }  #else  #define mcp251x_can_suspend NULL  #define mcp251x_can_resume NULL  #endif    static const struct spi_device_id mcp251x_id_table[] = {      { "mcp2510",    CAN_MCP251X_MCP2510 },      { "mcp2515",    CAN_MCP251X_MCP2515 },      { },  };    MODULE_DEVICE_TABLE(spi, mcp251x_id_table);    static struct spi_driver mcp251x_can_driver = {      .driver = {          .name = DEVICE_NAME,          .bus = &spi_bus_type,          .owner = THIS_MODULE,      },        .id_table = mcp251x_id_table,      .probe = mcp251x_can_probe,      .remove = __devexit_p(mcp251x_can_remove),      .suspend = mcp251x_can_suspend,      .resume = mcp251x_can_resume,  };    static int __init mcp251x_can_init(void)  {  DBG("init/n");      return spi_register_driver(&mcp251x_can_driver);  }    static void __exit mcp251x_can_exit(void)  {  DBG("exit/n");      spi_unregister_driver(&mcp251x_can_driver);  }    module_init(mcp251x_can_init);  module_exit(mcp251x_can_exit);    MODULE_AUTHOR("Chris Elston <celston@katalix.com>, "            "Christian Pellegrin <chripell@evolware.org>");  MODULE_DESCRIPTION("Microchip 251x CAN driver");  MODULE_LICENSE("GPL v2");  

******************************************************************几个疑点分析----以下讨论适用于te6410中断注册

static inline int __must_check  request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,          const char *name, void *dev)  {      return request_threaded_irq(irq, handler, NULL, flags, name, dev);  }  

原来他调用了request_threaded_irq(),并将中断处理函数(上半部)handler作为参数传递过去。追踪到request_threaded_irq,如下

int request_threaded_irq(unsigned int irq, irq_handler_t handler,               irq_handler_t thread_fn, unsigned long irqflags,               const char *devname, void *dev_id)  

其中要注意的两个参数,irq_handler_t   handler,中断处理函数上半部irq_handler_t   thread_fn,中断线程化,这样直接实现了中断处理函数的下半部,不必自己再去使用工作队列实现下半部了/*附工作队列的实现创建工作队列,并加入到一个工作者线程里让其去执行。这个工作者线程可以使内核现成的,也可以使自己心创建的。创建一个工作队列work_struct,使用DECLARE_WORK静态创建一个工作队列,参数包括队列名称和队列函数,也可使用INIT_WORK动态创建。创建一个新的工作者线程workqueue_struct,使用create_workqueue,返回值是工作者线程指针。将工作队列放到指定的工作者线程中去执行,int queue_work(struct workqueue_struct *wq, struct work_struct *work)将工作队列放到系统已有的events工作者线程中去执行,直接调用sheldule_work(&work)即可。工作者线程是一个内核线程,运行在进程上下文。工作者线程被唤醒时,会依次执行它里面的工作队列----组成了一个链表。*/搜索2.6.32.2源码,只发现一个同时使用了这两个参数的例子Broadcom B43 wireless driver,位于dribers/net/wireless/b43/main.c

err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,                 b43_interrupt_thread_handler,                 IRQF_SHARED, KBUILD_MODNAME, dev);  

其在中断上半部b43_interrupt_handler里禁止中断,在中断下半部b43_interrupt_thread_handler里批量读取数据然后重新使能中断(如果要清除中断标志位,则在使能之前先清除一下)。其余的例子几乎都只使用了一个参数thread_fn,而handler置为NULL,比如mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller

ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,          IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);  

又如本文要讨论的 mcp251x.c - CAN bus driver for Microchip 251x CAN Controller with SPI Interface

ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,            IRQF_TRIGGER_FALLING, DEVICE_NAME, priv);  

中断触发使用IRQF_TRIGGER_FALLING作为中断触发的条件。而mcp2515则是只要有数据发送完成(发给can总线)或有新的数据到来(来自can总线)就会置int引脚低电平,此脚接到0k6410的eint16,向ok6410发送中断中断信号。MCP2515有八个中断源。CANINTE寄存器包含了使能各中断源的中断使能位。 CANINTF 寄存器包含了各中断源的中断标志位。当发生中断时,INT 引脚将被MCP2515拉为低电平,并保持低电平状态直至MCU清除中断。中断只有在引起相应中断的条件消失后,才会被清除。mcp2515会自动清除中断吗?说明书上没写自动清除。mcp251x.c中却认为可以自动清除?如果使用低电平触发,则须存在中断上半部,在上半部里面先disable此中断,然后在下半部里面传输完数据之后再enable此中断。如果不在上半部disable此中断,则由于低电平一直存在,就会一直触发中断,从而一直执行中断上半部,(下半部根本就没机会执行到),造成死机。如果使用低电平触发,如果中断上半部函数指针设为NULL,那么即使在中断下半部执行disable此中断,也会造成死机。因为中断发生时,不会立即执行下半部函数,所以有可能没及时禁掉此中断,造成中断(此时仍然低电平)继续触发而使下半部线程大量重复的创建(或许)造成死机。如果使用下降沿触发,可以不存在上半部,即上半部函数指针可设为NULL,在下半部中可以先disable此中断,然后读取数据再清除中断标志位******************************************************************refer tolkd2http://blog.csdn.net/zhangjie201412/article/details/7067448


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表