zoukankan      html  css  js  c++  java
  • sja1000芯片can驱动程序

    应用层使用socketCan的方法:http://pan.baidu.com/s/1ntsvbb7#path=%252Floongson1%252Ftools%252Fcan

    功能:对can驱动程序的函数直接调用,而不经过设备驱动功能层、网络设备接口层、网络协议接口层

          像串口驱动程序调用can驱动程序函数时,首先要调用

      

    mytscan1_probe(&m_ppriv);
    mysja1000_set_bittiming(&m_ppriv);
    mysja1000_open(&m_ppriv);    

    这些函数,实现结构体的初始化以及相关寄存器的初始化操作。

    调用 netdev_tx_t mysja1000_start_xmit(struct can_frame *cf,struct sja1000_priv *priv) 进行数据的发送。

    调用 mysja1000_close()函数进行寄存器及中断的关闭操作

    样例:

    #include "mycan_drive.h"
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/ioport.h>
    #include <linux/init.h>
    #include <linux/console.h>
    #include <linux/sysrq.h>
    #include <linux/delay.h>
    #include <linux/platform_device.h>
    #include <linux/tty.h>
    #include <linux/ratelimit.h>
    #include <linux/tty_flip.h>
    #include <linux/serial_core.h>
    #include <linux/serial.h>
    #include <linux/serial_8250.h>
    #include <linux/nmi.h>
    #include <linux/mutex.h>
    #include <linux/slab.h>
    #include <linux/uaccess.h>
    #include <linux/pm_runtime.h>
    
    #include <asm/io.h>
    
    #include <asm/serial.h>
    
    
    
    static const struct can_bittiming_const mysja1000_bittiming_const = {
        .name = "",
        .tseg1_min = 1,
        .tseg1_max = 16,
        .tseg2_min = 1,
        .tseg2_max = 8,
        .sjw_max = 4,
        .brp_min = 1,
        .brp_max = 64,
        .brp_inc = 1,
    };
    
    
    
    struct sja1000_priv m_ppriv;
    
    
    extern struct uart_8250_port canserial_ports[15];
    
    
    
    static int can_update_spt(const struct can_bittiming_const *btc,
                  int sampl_pt, int tseg, int *tseg1, int *tseg2)
    {
        *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
        if (*tseg2 < btc->tseg2_min)
            *tseg2 = btc->tseg2_min;
        if (*tseg2 > btc->tseg2_max)
            *tseg2 = btc->tseg2_max;
        *tseg1 = tseg - *tseg2;
        if (*tseg1 > btc->tseg1_max) {
            *tseg1 = btc->tseg1_max;
            *tseg2 = tseg - *tseg1;
        }
        return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
    }
    
    
    
    static int can_calc_bittiming(struct can_priv *priv, struct can_bittiming *bt,
                      const struct can_bittiming_const *btc)
    {
    
        printk("Enter can_calc_bittiming
    ");
    
        long best_error = 1000000000, error = 0;
        int best_tseg = 0, best_brp = 0, brp = 0;
        int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
        int spt_error = 1000, spt = 0, sampl_pt;
        long rate;
        u64 v64;
    
        bt->bitrate = 1000000;
        /* Use CiA recommended sample points */
        if (bt->sample_point) {
            sampl_pt = bt->sample_point;
        } else {
            if (bt->bitrate > 800000)
                sampl_pt = 750;
            else if (bt->bitrate > 500000)
                sampl_pt = 800;
            else
                sampl_pt = 875;
        }
    
        /* tseg even = round down, odd = round up */
        for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
             tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
            tsegall = 1 + tseg / 2;
            /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
            brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
            /* chose brp step which is possible in system */
            brp = (brp / btc->brp_inc) * btc->brp_inc;
            if ((brp < btc->brp_min) || (brp > btc->brp_max))
                continue;
            rate = priv->clock.freq / (brp * tsegall);
            error = bt->bitrate - rate;
            /* tseg brp biterror */
            if (error < 0)
                error = -error;
            if (error > best_error)
                continue;
            best_error = error;
            if (error == 0) {
                spt = can_update_spt(btc, sampl_pt, tseg / 2,
                             &tseg1, &tseg2);
                error = sampl_pt - spt;
                if (error < 0)
                    error = -error;
                if (error > spt_error)
                    continue;
                spt_error = error;
            }
            best_tseg = tseg / 2;
            best_brp = brp;
            if (error == 0)
                break;
        }
    
        // if (best_error) {
        //     /* Error in one-tenth of a percent */
        //     error = (best_error * 1000) / bt->bitrate;
        //     if (error > CAN_CALC_MAX_ERROR) {
        //         // netdev_err(dev,
        //         //        "bitrate error %ld.%ld%% too high
    ",
        //         //        error / 10, error % 10);
        //         return -EDOM;
        //     } else {
        //         // netdev_warn(dev, "bitrate error %ld.%ld%%
    ",
        //         //         error / 10, error % 10);
        //     }
        // }
    
        /* real sample point */
        bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg,
                          &tseg1, &tseg2);
    
        v64 = (u64)best_brp * 1000000000UL;
        do_div(v64, priv->clock.freq);
        bt->tq = (u32)v64;
        bt->prop_seg = tseg1 / 2;
        bt->phase_seg1 = tseg1 - bt->prop_seg;
        bt->phase_seg2 = tseg2;
    
        /* check for sjw user settings */
        if (!bt->sjw || !btc->sjw_max)
            bt->sjw = 1;
        else {
            /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
            if (bt->sjw > btc->sjw_max)
                bt->sjw = btc->sjw_max;
            /* bt->sjw must not be higher than tseg2 */
            if (tseg2 < bt->sjw)
                bt->sjw = tseg2;
        }
    
        bt->brp = best_brp;
        /* real bit-rate */
        bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
    
       printk("can_calc_bittiming bitrate:%d
    ",bt->bitrate);
    
        return 0;
    }
    
    
    
    
    int mysja1000_set_bittiming(struct sja1000_priv *priv)
    {
        
    
        printk("Enter mysja1000_set_bittiming
    ");
        can_calc_bittiming(&priv->can,&priv->can.bittiming,&mysja1000_bittiming_const);
    
    
    
        struct can_bittiming *bt = &priv->can.bittiming;
        u8 btr0, btr1;
    
        btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
        btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
            (((bt->phase_seg2 - 1) & 0x7) << 4);
        if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
            btr1 |= 0x80;
    
        // netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x
    ", btr0, btr1);
    
        printk("mysja1000_set_bittiming BTR0=0x%02x BTR1=0x%02x
    ",btr0,btr1);
        priv->write_reg(priv, SJA1000_BTR0, btr0);
        priv->write_reg(priv, SJA1000_BTR1, btr1);
    
        return 0;
    }
    
    
    
    // 对发送接收计数失败的统计
    int mysja1000_get_berr_counter(const struct sja1000_priv *priv,
                    struct can_berr_counter *bec)
    {
        
        bec->txerr = priv->read_reg(priv, SJA1000_TXERR);
        bec->rxerr = priv->read_reg(priv, SJA1000_RXERR);
    
        return 0;
    }
    
    
    
    
    
    /* Read SJA1000 register */
    static u8 mytscan1_read(const struct sja1000_priv *priv, int reg)
    {
        return inb((unsigned long)priv->reg_base + reg);
    }
    
    /* Write SJA1000 register */
    static void mytscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
    {
        outb(val, (unsigned long)priv->reg_base + reg);
    }
    
    void myset_normal_mode(struct sja1000_priv *priv)
    {
    
        printk("Enter myset_normal_mode
     ");
        unsigned char status = priv->read_reg(priv, SJA1000_MOD);
        u8 mod_reg_val = 0x00;
        int i;
    
        for (i = 0; i < 100; i++) {
            /* check reset bit */
            if ((status & MOD_RM) == 0) {
                priv->can.state = CAN_STATE_ERROR_ACTIVE;
                /* enable interrupts */
                if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
                    priv->write_reg(priv, SJA1000_IER, IRQ_ALL);
                else
                    priv->write_reg(priv, SJA1000_IER,
                            IRQ_ALL & ~IRQ_BEI);
                return;
            }
    
            /* set chip to normal mode */
            if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
                mod_reg_val |= MOD_LOM;
            if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK)
                mod_reg_val |= MOD_STM;
            priv->write_reg(priv, SJA1000_MOD, mod_reg_val);
    
            udelay(10);
    
            status = priv->read_reg(priv, SJA1000_MOD);
        }
    
    }
    
    
    
    void myset_reset_mode(struct sja1000_priv *priv)
    {
    
        unsigned char status = priv->read_reg(priv, SJA1000_MOD);
        int i;
    
        /* disable interrupts */
        priv->write_reg(priv, SJA1000_IER, IRQ_OFF);
    
        for (i = 0; i < 100; i++) {
            /* check reset bit */
            if (status & MOD_RM) {
                priv->can.state = CAN_STATE_STOPPED;
                return;
            }
    
            /* reset chip */
            priv->write_reg(priv, SJA1000_MOD, MOD_RM);
            udelay(10);
            status = priv->read_reg(priv, SJA1000_MOD);
        }
    
    }
    
    
    // open can  
    
    
    
    /******************************************************************************/
    
    void mysja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
    {
        unsigned long flags;
    
        /*
         * The command register needs some locking and time to settle
         * the write_reg() operation - especially on SMP systems.
         */
        spin_lock_irqsave(&priv->cmdreg_lock, flags);
        priv->write_reg(priv, SJA1000_CMR, val);
        priv->read_reg(priv, SJA1000_SR);
        spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
    }
    /*
     * initialize SJA1000 chip:
     *   - reset chip
     *   - set output mode
     *   - set baudrate
     *   - enable interrupts
     *   - start operating mode
     */
    void mychipset_init(struct sja1000_priv *priv )
    {
    
        printk("Enter the mychipset_init
    ");
    
        /* set clock divider and output control register */
    #if defined(CONFIG_LS1X_CAN0) || defined(CONFIG_LS1X_CAN1)
        mysja1000_write_cmdreg(priv, 0x80);
    #else
        priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
    #endif
    
        /* set acceptance filter (accept all) */
        priv->write_reg(priv, SJA1000_ACCC0, 0x00);
        priv->write_reg(priv, SJA1000_ACCC1, 0x00);
        priv->write_reg(priv, SJA1000_ACCC2, 0x00);
        priv->write_reg(priv, SJA1000_ACCC3, 0x00);
    
        priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
        priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
        priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
        priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
        priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
    }
    
    
    
    
    
    
    
    void mysja1000_start(struct sja1000_priv *priv)
    {
    
        
        printk("Enter the mysja1000_start
    ");
    
    
        /* leave reset mode */
        if (priv->can.state != CAN_STATE_STOPPED)
            myset_reset_mode(priv);
    
        /* Initialize chip if uninitialized at this stage */
        if (!(priv->read_reg(priv, SJA1000_CDR) & CDR_PELICAN))
            mychipset_init(priv);
    
        /* Clear error counters and error code capture */
        priv->write_reg(priv, SJA1000_TXERR, 0x0);
        priv->write_reg(priv, SJA1000_RXERR, 0x0);
        priv->read_reg(priv, SJA1000_ECC);
    
        /* leave reset mode */
        myset_normal_mode(priv);
    }
    
    
    int mysja1000_set_mode(struct sja1000_priv *priv, enum can_mode mode)
    {
        switch (mode) {
        case CAN_MODE_START:
            mysja1000_start(priv);
            // if (netif_queue_stopped(dev))
            //     netif_wake_queue(dev);
            break;
    
        default:
            return -EOPNOTSUPP;
        }
    
        return 0;
    }
    
    
    
    static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
    {
        return ioread8(priv->reg_base + reg);
    }
    
    static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val)
    {
        iowrite8(val, priv->reg_base + reg);
    }
    
    
    
    
    
    
    
    
    int calc_com_addr(int can_id)
    {
         int device_addr, sub_addr;
         device_addr = can_id & 0x0F;
         sub_addr = (can_id & 0x70)>>4;
    
         return sub_addr+(device_addr-1)*5;
    }
    
    
    
    
    
    
    
    
    
    
    
    void mysja1000_rx(struct sja1000_priv *priv)
    {
    
        // struct net_device_stats *stats = &dev->stats;
        // struct can_frame can_buff;
        char length_can;
        // struct can_frame *cf = &can_buff;
        struct sk_buff skb;
        uint8_t fi;
        uint8_t dreg;
        canid_t id;
        int i;
        unsigned ch;
        printk("Enter the mysja1000_rx
    ");
    
    /*******************************/
        // 进行数据的获取
        /* create zero'ed CAN frame buffer */
        // skb = alloc_can_skb(dev, &cf);
    
        // if (skb == NULL)
        //     return;
    
        fi = priv->read_reg(priv, SJA1000_FI);
    
        if (fi & SJA1000_FI_FF) {
            printk("mysja1000_rx expand frame
    ");
            /* extended frame format (EFF) */
            dreg = SJA1000_EFF_BUF;
            id = (priv->read_reg(priv, SJA1000_ID1) << 21)
                | (priv->read_reg(priv, SJA1000_ID2) << 13)
                | (priv->read_reg(priv, SJA1000_ID3) << 5)
                | (priv->read_reg(priv, SJA1000_ID4) >> 3);
            id |= CAN_EFF_FLAG;
        } else {
            /* standard frame format (SFF) */
            dreg = SJA1000_SFF_BUF;
            id = (priv->read_reg(priv, SJA1000_ID1) << 3)
                | (priv->read_reg(priv, SJA1000_ID2) >> 5);
        }
    
        // cf->can_dlc = get_can_dlc(fi & 0x0F);
    
    
        length_can = get_can_dlc(fi & 0x0F);
    
    
        int curr_index =  calc_com_addr(id);
    
        printk("receive from can's com addr:%d
    ",curr_index);
        struct uart_port *curr_port = &canserial_ports[curr_index].port;
    
        if (fi & SJA1000_FI_RTR) {
            id |= CAN_RTR_FLAG;
        } else {
            for (i = 0; i < length_can; i++)
            {
    
                ch = priv->read_reg(priv, dreg++);
    
                uart_insert_char(curr_port, 0, 0x02, ch, 0);
    
                curr_port->icount.tx++;
                // cf->data[i] = priv->read_reg(priv, dreg++);
                // printk("rx data %x
    ",data[i]);
            }
    
        }
    
        spin_unlock(&curr_port->lock);
        tty_flip_buffer_push(&curr_port->state->port);
        spin_lock(&curr_port->lock);
    
    
        /* release receive buffer */
        mysja1000_write_cmdreg(priv, CMD_RRB);
    
    
    
    }
    
    
    
    
    irqreturn_t mysja1000_interrupt(int irq, void *dev_id)
    {
    
    
    
         struct sja1000_priv *priv = (struct sja1000_priv*)dev_id;
    
         printk("mysja1000_interrupt
    ");
    
    
    
        // struct net_device_stats *stats = &dev->stats;
    
        uint8_t isrc, status;
        int n = 0;
    
        if (priv->pre_irq)
            priv->pre_irq(priv);
    
        /* Shared interrupts and IRQ off? */
        if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
            goto out;
    
        while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
               (n < SJA1000_MAX_IRQ)) {
    
            status = priv->read_reg(priv, SJA1000_SR);
            /* check for absent controller due to hw unplug */
            // if (status == 0xFF && sja1000_is_absent(priv))
            //     goto out;
    
            // if (isrc & IRQ_WUI)
            //     netdev_warn(dev, "wakeup interrupt
    ");
    
            if (isrc & IRQ_TI) {
                /* transmission buffer released */
                if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
                    !(status & SR_TCS)) {
                    // stats->tx_errors++;
                    // can_free_echo_skb(dev, 0);
                } else {
                    /* transmission complete */
                    // stats->tx_bytes +=
                        priv->read_reg(priv, SJA1000_FI) & 0xf;
                    // stats->tx_packets++;
                }
                // can_led_event(dev, CAN_LED_EVENT_TX);
            }
            if (isrc & IRQ_RI) {
                /* receive interrupt */
                while (status & SR_RBS) {
                    mysja1000_rx(priv);
                    status = priv->read_reg(priv, SJA1000_SR);
                    /* check for absent controller */
                    // if (status == 0xFF && sja1000_is_absent(priv))
                    //     goto out;
                }
            }
            if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
                /* error interrupt */
                // if (sja1000_err(dev, isrc, status))
                //     break;
            }
            n++;
        }
    
    
    out:
        if (priv->post_irq)
            priv->post_irq(priv);
    
        // if (n >= SJA1000_MAX_IRQ)
        //     netdev_dbg(dev, "%d messages handled in ISR", n);
    
        return (n) ? IRQ_HANDLED : IRQ_NONE;
    }
    
    
    
    EXPORT_SYMBOL_GPL(mysja1000_interrupt);
    
    
    int mysja1000_open(struct sja1000_priv *priv)
    {
    
    
        printk("enter mysja1000_open
    ");
    
        myset_reset_mode(priv);
    
    
    
    /***********************open_candev()**********************/
        // err = open_candev(dev); 等效
        if (!priv->can.bittiming.bitrate) {
            printk("bit-timing not yet defined
    ");
            return -EINVAL;
        }
    
        printk("priv->can.bittiming.bitrate is %d
    " ,priv->can.bittiming.bitrate);
    
        if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) &&
            (!priv->can.data_bittiming.bitrate ||
             (priv->can.data_bittiming.bitrate < priv->can.bittiming.bitrate))) {
                // netdev_err(dev, "incorrect/missing data bit-timing
    ");
            printk("incorrect/missing data bit-timing
    ");
            return -EINVAL;
        }
    
    
        // mysja1000_set_mode(priv, CAN_MODE_START);
        
    /*********************************************/
    
    
    // 请求中断   待解决
    // 第一个参数irq:申请的硬件中断号;
    
    // 第二个参数handler:是一个函数指针,向系统登记的中断处理函数,是一个回调函数,当中断发生时,系统调用这个函数,传入的参数包括中断设备 id,寄存器值。
    
    // 第三个参数flags:指定了快速中断或中断共享等中断处理属性。
    
    // 第四个参数devices:指定设备驱动程序的名称。
    
    // 第五个参数dev_id:传入中断处理程序的参数,可以为NULL,在注册共享中断时,此参数不能为NULL,作为共享中断时的中断区别参数。
        int err = request_irq(14, mysja1000_interrupt, priv->irq_flags,
                      "canserial8250", (void *)priv);
       
        if(!err)
        {
            printk("request_irq failed
    ");
        }
    
        mysja1000_start(priv);
    
    }
    
    
    
    
    
    
    int mysja1000_close(struct sja1000_priv *priv)
    {
    
    
        printk("mysja1000_close
    ");
        myset_reset_mode(priv);
    
        if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER))
            free_irq(14, (void *)priv);
    
        // close_candev(dev);
    
    
        return 0;
    }
    
    
    
    
    
    /*
     * transmit a CAN message
     * message layout in the sk_buff should be like this:
     * xx xx xx xx     ff     ll   00 11 22 33 44 55 66 77
     * [  can-id ] [flags] [len] [can data (up to 8 bytes]
     */
    // netdev_tx_t mysja1000_start_xmit(struct sk_buff *skb,
                            // struct sja1000_priv *priv)
    
    netdev_tx_t mysja1000_start_xmit(struct can_frame *cf,
                            struct sja1000_priv *priv)
    {
    
     //  对sk_buff 结构体定义其id、can_dlc、data
    
        // struct can_frame *cf = (struct can_frame *)skb->data;
    
        uint8_t fi;
        uint8_t dlc;
        canid_t id;
        uint8_t dreg;
        u8 cmd_reg_val = 0x00;
        int i;
        printk("Enter the mysja1000_start_xmit
    ");
        printk("the start send data:%s
    ",cf->data);
    
    
        // if (can_dropped_invalid_skb(dev, skb))
        //     return NETDEV_TX_OK;
    
        // netif_stop_queue(dev);
    
        fi = dlc = cf->can_dlc;
        id = cf->can_id;
    
        if (id & CAN_RTR_FLAG)
            fi |= SJA1000_FI_RTR;
    
    // CAN_EFF_FLAG 扩展帧  用扩展帧对数据进行发送
        if (id & CAN_EFF_FLAG) {
            printk("Enter mysja1000_start_xmit expand frame 
    ");
            fi |= SJA1000_FI_FF;
            dreg = SJA1000_EFF_BUF;
            priv->write_reg(priv, SJA1000_FI, fi);
            priv->write_reg(priv, SJA1000_ID1, (id & 0x1fe00000) >> 21);
            priv->write_reg(priv, SJA1000_ID2, (id & 0x001fe000) >> 13);
            priv->write_reg(priv, SJA1000_ID3, (id & 0x00001fe0) >> 5);
            priv->write_reg(priv, SJA1000_ID4, (id & 0x0000001f) << 3);
        } else {
            dreg = SJA1000_SFF_BUF;
            priv->write_reg(priv, SJA1000_FI, fi);
            priv->write_reg(priv, SJA1000_ID1, (id & 0x000007f8) >> 3);
            priv->write_reg(priv, SJA1000_ID2, (id & 0x00000007) << 5);
        }
    
        for (i = 0; i < dlc; i++)
        { 
            printk("send data:%d
    ", cf->data[i]);
            priv->write_reg(priv, dreg++, cf->data[i]);
        }
    
        // can_put_echo_skb(skb, dev, 0);
    
        if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
            cmd_reg_val |= CMD_AT;
    
        if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
            cmd_reg_val |= CMD_SRR;
        else
            cmd_reg_val |= CMD_TR;
    
        mysja1000_write_cmdreg(priv, cmd_reg_val);
    
        return NETDEV_TX_OK;
    }
    
    
    int sja1000_is_absent(struct sja1000_priv *priv)
    {    
        printk("sja1000_is_absent
    ");
        return (priv->read_reg(priv, SJA1000_MOD) == 0xFF);
    }
    
    
    int myregister_sja1000dev(struct sja1000_priv *priv)
    {
        int ret;
    
        printk("Enter myregister_sja1000dev
    ");
        // if (!mysja1000_probe_chip(priv))
        //     return -ENODEV;
    
        if (priv->reg_base && sja1000_is_absent(priv)) {
            printk("probing failed
    ");
            return 0;
        }
    
    
        // dev->flags |= IFF_ECHO;     we support local echo 
        // dev->netdev_ops = &sja1000_netdev_ops;
    
        myset_reset_mode(priv);
        mychipset_init(priv);
    
        // ret =  register_candev(dev);
    
        // if (!ret)
            // devm_can_led_init(dev);
    
        // return ret;
    }
    
    
    
    // probe 这一块没什么问题
    int mytscan1_probe(struct sja1000_priv *priv)
    {
    
        printk("Enter mytscan1_probe
    ");
        priv->irq_flags = 0;
        // dev->irq = 14;
        priv->reg_base = (void __iomem *)0xbfe50000;
        priv->can.clock.freq = 41406250;
        priv->ocr = 88;
        priv->cdr = 64;
    
        priv->read_reg = sp_read_reg8;
        priv->write_reg = sp_write_reg8;
    
    
    
    //alloc_sja1000dev
        priv->dev = NULL;
        priv->can.bittiming_const = &mysja1000_bittiming_const;
        priv->can.do_set_bittiming = mysja1000_set_bittiming;
        priv->can.do_set_mode = mysja1000_set_mode;
        priv->can.do_get_berr_counter = mysja1000_get_berr_counter;
        priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
                           CAN_CTRLMODE_LISTENONLY |
                           CAN_CTRLMODE_3_SAMPLES |
                           CAN_CTRLMODE_ONE_SHOT |
                           CAN_CTRLMODE_BERR_REPORTING |
                           CAN_CTRLMODE_PRESUME_ACK;
    
    
    
       myregister_sja1000dev(priv);
    
        return 0;
    }

        

  • 相关阅读:
    推荐三首适合午休时听的歌
    我要用全身心的爱来迎接每一天!
    过年,别忘了给父母买点东西
    外来务工的人们,你们真是不容易啊!
    新年最新的100句超牛的语言(转)
    最近Gmail扩容的很快
    老板其人
    乒乓爱好者请进:看看你是第几级?
    上海轨道交通地图电子版(提供下载)
    windows XP使用秘籍(包括空当接龙秘籍)
  • 原文地址:https://www.cnblogs.com/hzijone/p/5242455.html
Copyright © 2011-2022 走看看