国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

can3--socketcan之mcp251x.c

2019-11-09 14:29:48
字體:
供稿:網(wǎng)友

轉(zhuǎn)自http://www.cnblogs.com/-song/archive/2012/05/24/3331872.html

spi驅(qū)動(dòng)結(jié)構(gòu)見http://blog.csdn.net/songQQnew/article/details/7037583mcp251x.c幾乎是抄襲dm9000的寫作格式參考  

dm9000 driver 1

 理清一下驅(qū)動(dòng)的線索******************************************************************在init函數(shù)中注冊(cè)spi驅(qū)動(dòng)mcp251x_can_driver

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

在spi驅(qū)動(dòng)mcp251x_can_driver的PRobe函數(shù)中分配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;      }      //注冊(cè)net_device      register_candev(net);        //net_device的Operation結(jié)構(gòu)體指定了操作函數(shù)集合       static const struct net_device_ops mcp251x_netdev_ops = {      .ndo_open = mcp251x_open,      .ndo_stop = mcp251x_stop,      .ndo_start_xmit = mcp251x_hard_start_xmit,      };  }  

應(yīng)用層執(zhí)行ifconfig can0 up時(shí)會(huì)調(diào)用到mcp251x_open在mcp251x_open函數(shù)中,

//打開設(shè)備  open_candev(net);  //申請(qǐng)中斷  ret = request_irq(spi->irq, mcp251x_can_irq, /*IRQF_DISABLED |*/ IRQF_TRIGGER_LOW ,  DEVICE_NAME, priv);  //初始化工作隊(duì)列,當(dāng)做中斷(接收)下半部,用于處理接收  INIT_WORK(&priv->irq_work,can_irq_work);  //初始化工作隊(duì)列,用于處理發(fā)送  INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);  

應(yīng)用層執(zhí)行write socket時(shí)會(huì)調(diào)用到mcp251x_hard_start_xmit,在 mcp251x_hard_start_xmit函數(shù)中,

//停止協(xié)議棧向驅(qū)動(dòng)發(fā)送數(shù)據(jù)(在發(fā)送數(shù)據(jù)的時(shí)候需要停止協(xié)議棧發(fā)來新的需要發(fā)送出去的數(shù)據(jù)),發(fā)送完成后會(huì)重新啟用  netif_stop_queue(net);  //啟動(dòng)發(fā)送工作隊(duì)列,將數(shù)據(jù)(skb)發(fā)送出去  priv->tx_skb = skb;  queue_work(priv->wq, &priv->tx_work);  

具體看一下這個(gè)發(fā)送工作隊(duì)列函數(shù)

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);  }  

怎么接收呢?當(dāng)然是在中斷處理函數(shù)中接收,有中斷產(chǎn)生時(shí),會(huì)啟用一個(gè)負(fù)責(zé)接受的工作隊(duì)列,即中斷下半部,去接收。并將接收到的數(shù)據(jù)保存,以供應(yīng)用層使用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);//禁止中斷,工作隊(duì)列函數(shù)中接收完成時(shí)會(huì)重新使能中斷         if (!work_pending(&priv->irq_work))          queue_work(priv->wq, &priv->irq_work);//調(diào)用工作隊(duì)列函數(shù)         return IRQ_HANDLED;  }  

接收工作隊(duì)列函數(shù)

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里有數(shù)據(jù)。                  //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) {//如果是發(fā)送完成中斷                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接收到數(shù)據(jù)的中斷                mcp251x_hw_rx(spi, 1);//接收              /* the MCP2515 does this automatically */              if (mcp251x_is_2510(spi))                  clear_intf |= CANINTF_RX1IF;//清除mcp251x里的中斷標(biāo)志          }                    /* receive buffer 0 */          if (intf & CANINTF_RX0IF) {//如果是從mcp251x的buffer 0接收到數(shù)據(jù)的中斷                mcp251x_hw_rx(spi, 0);//接收mcp2515的rxb0里的數(shù)據(jù),見下              /*              * Free one buffer ASAP              * (The MCP2515 does this automatically.)              */              if (mcp251x_is_2510(spi))                  mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);//清除mcp251x里的中斷標(biāo)志          }                 /* 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;//中斷設(shè)置      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直接發(fā)送的數(shù)據(jù)/n");  for( i=0;i<len;i++)  {  DBG("priv->spi_tx_buf[%d]=%x/n",i,priv->spi_tx_buf[i]);  }    DBG("打印spi直接收到的數(shù)據(jù)/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  //根據(jù)mcp2515手冊(cè)p64,使用spi接口讀取寄存器的步驟是發(fā)送 命令03+地址  //接收到的寄存器數(shù)據(jù)在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);  ////接收到的寄存器數(shù)據(jù)在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  //根據(jù)mcp2515手冊(cè)p64,使用spi接口寫寄存器的步驟是發(fā)送 命令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  //位修改指令,對(duì)可執(zhí)行位操作的寄存器有效      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,還需要指定使用那個(gè)發(fā)送緩沖區(qū)發(fā)送數(shù)據(jù)  //      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("打印是否擴(kuò)展幀/n");      if (exide)          {          sid = (frame->can_id & CAN_EFF_MASK) >> 18;          DBG("是擴(kuò)展幀/n");          }      else          {          sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */          DBG("是標(biāo)準(zhǔn)幀/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的數(shù)據(jù)/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);//請(qǐng)求發(fā)送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的發(fā)送和接收緩沖區(qū)都設(shè)為14 因?yàn)閙cp2515共返回14個(gè)字節(jié),假如是讀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);// 接收數(shù)據(jù)    DBG("打印從spi接收到buf里的數(shù)據(jù)/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("打印是否是擴(kuò)展幀/n");      if (buf[RXBSIDL_OFF] & RXBSIDL_IDE) {  //buf[RXBSIDL_OFF]即buf[2]即寄存器RXBnSIDL的第4位表示是否是擴(kuò)展幀  DBG("是擴(kuò)展幀/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("是標(biāo)準(zhǔn)幀/n");          /* Standard ID format */    //RXBSIDH的全8位和RXBSIDL的高3位即11位共同組成標(biāo)準(zhǔn)幀的標(biāo)識(shí)符,詳見mcp2515手冊(cè),  //所以理論上一條can總線最多可分辨2048個(gè)設(shè)備(擴(kuò)展幀也是11位標(biāo)識(shí)符)  //如果  //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,標(biāo)準(zhǔn)幀不使用  //buf[4]=寄存器RXBEID0,標(biāo)準(zhǔn)幀不使用  //buf[5]=寄存器RXBDLC=數(shù)據(jù)段長(zhǎng)度      frame->can_dlc = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);  //buf[6]-buf[13]=8個(gè)數(shù)據(jù)寄存器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里的數(shù)據(jù)/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("從應(yīng)用層收到發(fā)送命令/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("要發(fā)送的數(shù)據(jù)是skb/n");  DBG("啟動(dòng)發(fā)送隊(duì)列/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);  //刪除定時(shí)器        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("進(jìn)入發(fā)送隊(duì)列/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里的數(shù)據(jù)/n");  for(i=0;i<20;i++)  {  DBG("priv->tx_skb->data[%d]=%x/n",i,priv->tx_skb->data[i]);  }  //將skb里的數(shù)據(jù)給can_frame以便組織發(fā)送              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;  //發(fā)送              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);        //修改定時(shí)器  }*/      static irqreturn_t mcp251x_can_irq(int irq, void *dev_id)  {  DBG("有中斷產(chǎn)生/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);  //關(guān)中斷,為什么disable_irq死機(jī)         //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);  //關(guān)中斷,為什么disable_irq死機(jī)        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("進(jìn)入中斷下半部/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);  //讀取中斷標(biāo)志寄存器,用于判斷是什么中斷                  DBG("中斷標(biāo)志=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("是發(fā)送完成中斷: /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("是接收到數(shù)據(jù)中斷: /n");  DBG("receive buffer1有數(shù)據(jù)/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("是接收到數(shù)據(jù)中斷: /n");  DBG("receive buffer0有數(shù)據(jù)/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);   //初始化定時(shí)器  //        check_timer.expires=jiffies+HZ;  //        check_timer.function=&check_timer_callback;  //        check_timer.data=(long)priv;          //add_timer(&check_timer);        //添加定時(shí)器*/        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");  

******************************************************************幾個(gè)疑點(diǎn)分析----以下討論適用于te6410中斷注冊(cè)

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);  }  

原來他調(diào)用了request_threaded_irq(),并將中斷處理函數(shù)(上半部)handler作為參數(shù)傳遞過去。追蹤到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)  

其中要注意的兩個(gè)參數(shù),irq_handler_t   handler,中斷處理函數(shù)上半部irq_handler_t   thread_fn,中斷線程化,這樣直接實(shí)現(xiàn)了中斷處理函數(shù)的下半部,不必自己再去使用工作隊(duì)列實(shí)現(xiàn)下半部了/*附工作隊(duì)列的實(shí)現(xiàn)創(chuàng)建工作隊(duì)列,并加入到一個(gè)工作者線程里讓其去執(zhí)行。這個(gè)工作者線程可以使內(nèi)核現(xiàn)成的,也可以使自己心創(chuàng)建的。創(chuàng)建一個(gè)工作隊(duì)列work_struct,使用DECLARE_WORK靜態(tài)創(chuàng)建一個(gè)工作隊(duì)列,參數(shù)包括隊(duì)列名稱和隊(duì)列函數(shù),也可使用INIT_WORK動(dòng)態(tài)創(chuàng)建。創(chuàng)建一個(gè)新的工作者線程workqueue_struct,使用create_workqueue,返回值是工作者線程指針。將工作隊(duì)列放到指定的工作者線程中去執(zhí)行,int queue_work(struct workqueue_struct *wq, struct work_struct *work)將工作隊(duì)列放到系統(tǒng)已有的events工作者線程中去執(zhí)行,直接調(diào)用sheldule_work(&work)即可。工作者線程是一個(gè)內(nèi)核線程,運(yùn)行在進(jìn)程上下文。工作者線程被喚醒時(shí),會(huì)依次執(zhí)行它里面的工作隊(duì)列----組成了一個(gè)鏈表。*/搜索2.6.32.2源碼,只發(fā)現(xiàn)一個(gè)同時(shí)使用了這兩個(gè)參數(shù)的例子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里批量讀取數(shù)據(jù)然后重新使能中斷(如果要清除中斷標(biāo)志位,則在使能之前先清除一下)。其余的例子幾乎都只使用了一個(gè)參數(shù)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);  

中斷觸發(fā)使用IRQF_TRIGGER_FALLING作為中斷觸發(fā)的條件。而mcp2515則是只要有數(shù)據(jù)發(fā)送完成(發(fā)給can總線)或有新的數(shù)據(jù)到來(來自can總線)就會(huì)置int引腳低電平,此腳接到0k6410的eint16,向ok6410發(fā)送中斷中斷信號(hào)。MCP2515有八個(gè)中斷源。CANINTE寄存器包含了使能各中斷源的中斷使能位。 CANINTF 寄存器包含了各中斷源的中斷標(biāo)志位。當(dāng)發(fā)生中斷時(shí),INT 引腳將被MCP2515拉為低電平,并保持低電平狀態(tài)直至MCU清除中斷。中斷只有在引起相應(yīng)中斷的條件消失后,才會(huì)被清除。mcp2515會(huì)自動(dòng)清除中斷嗎?說明書上沒寫自動(dòng)清除。mcp251x.c中卻認(rèn)為可以自動(dòng)清除?如果使用低電平觸發(fā),則須存在中斷上半部,在上半部里面先disable此中斷,然后在下半部里面?zhèn)鬏斖陻?shù)據(jù)之后再enable此中斷。如果不在上半部disable此中斷,則由于低電平一直存在,就會(huì)一直觸發(fā)中斷,從而一直執(zhí)行中斷上半部,(下半部根本就沒機(jī)會(huì)執(zhí)行到),造成死機(jī)。如果使用低電平觸發(fā),如果中斷上半部函數(shù)指針設(shè)為NULL,那么即使在中斷下半部執(zhí)行disable此中斷,也會(huì)造成死機(jī)。因?yàn)橹袛喟l(fā)生時(shí),不會(huì)立即執(zhí)行下半部函數(shù),所以有可能沒及時(shí)禁掉此中斷,造成中斷(此時(shí)仍然低電平)繼續(xù)觸發(fā)而使下半部線程大量重復(fù)的創(chuàng)建(或許)造成死機(jī)。如果使用下降沿觸發(fā),可以不存在上半部,即上半部函數(shù)指針可設(shè)為NULL,在下半部中可以先disable此中斷,然后讀取數(shù)據(jù)再清除中斷標(biāo)志位******************************************************************refer tolkd2http://blog.csdn.net/zhangjie201412/article/details/7067448


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 邵武市| 海淀区| 西盟| 永年县| 长宁县| 鄂尔多斯市| 桦南县| 内黄县| 滨州市| 兴和县| 大荔县| 万安县| 女性| 江津市| 巴彦淖尔市| 阿城市| 绿春县| 尉犁县| 阿克| 台北市| 四子王旗| 衡山县| 梁山县| 将乐县| 扎鲁特旗| 黎城县| 万山特区| 北海市| 乳山市| 江达县| 清河县| 永平县| 屯留县| 锡林郭勒盟| 靖西县| 长沙市| 汝州市| 扶余县| 融水| 平远县| 沁水县|