应用层使用socketCan的方法:http://pan.baidu.com/s/1ntsvbb7
功能:对can驱动程序的函数直接调用,而不经过设备驱动功能层、网络设备接口层、网络协议接口层
像串口驱动程序调用can驱动程序函数时,首先要调用
mytscan1_probe&m_ppriv); mysja1000_set_bittiming&m_ppriv); mysja1000_open&m_ppriv);
这些函数,实现结构体的初始化以及相关寄存器的初始化操作。
调用 netdev_tx_t mysja1000_start_xmitstruct 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_sptconst 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_bittimingstruct 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_sptbtc, 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_errdev, // // "bitrate error %ld.%ld%% too high ", // // error / 10, error % 10); // return -EDOM; // } else { // // netdev_warndev, "bitrate error %ld.%ld%% ", // // error / 10, error % 10); // } // } /* real sample point */ bt->sample_point = can_update_sptbtc, sampl_pt, best_tseg, &tseg1, &tseg2); v64 = u64)best_brp * 1000000000UL; do_divv64, 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_bittimingstruct 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_infodev, "setting BTR0=0x%02x BTR1=0x%02x ", btr0, btr1); printk"mysja1000_set_bittiming BTR0=0x%02x BTR1=0x%02x ",btr0,btr1); priv->write_regpriv, SJA1000_BTR0, btr0); priv->write_regpriv, SJA1000_BTR1, btr1); return 0; } // 对发送接收计数失败的统计 int mysja1000_get_berr_counterconst struct sja1000_priv *priv, struct can_berr_counter *bec) { bec->txerr = priv->read_regpriv, SJA1000_TXERR); bec->rxerr = priv->read_regpriv, SJA1000_RXERR); return 0; } /* Read SJA1000 register */ static u8 mytscan1_readconst struct sja1000_priv *priv, int reg) { return inbunsigned long)priv->reg_base + reg); } /* Write SJA1000 register */ static void mytscan1_writeconst struct sja1000_priv *priv, int reg, u8 val) { outbval, unsigned long)priv->reg_base + reg); } void myset_normal_modestruct sja1000_priv *priv) { printk"Enter myset_normal_mode "); unsigned char status = priv->read_regpriv, 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_regpriv, SJA1000_IER, IRQ_ALL); else priv->write_regpriv, 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_regpriv, SJA1000_MOD, mod_reg_val); udelay10); status = priv->read_regpriv, SJA1000_MOD); } } void myset_reset_modestruct sja1000_priv *priv) { unsigned char status = priv->read_regpriv, SJA1000_MOD); int i; /* disable interrupts */ priv->write_regpriv, 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_regpriv, SJA1000_MOD, MOD_RM); udelay10); status = priv->read_regpriv, SJA1000_MOD); } } // open can /******************************************************************************/ void mysja1000_write_cmdregstruct 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_regpriv, SJA1000_CMR, val); priv->read_regpriv, 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_initstruct sja1000_priv *priv ) { printk"Enter the mychipset_init "); /* set clock divider and output control register */ #if definedCONFIG_LS1X_CAN0) || definedCONFIG_LS1X_CAN1) mysja1000_write_cmdregpriv, 0x80); #else priv->write_regpriv, SJA1000_CDR, priv->cdr | CDR_PELICAN); #endif /* set acceptance filter accept all) */ priv->write_regpriv, SJA1000_ACCC0, 0x00); priv->write_regpriv, SJA1000_ACCC1, 0x00); priv->write_regpriv, SJA1000_ACCC2, 0x00); priv->write_regpriv, SJA1000_ACCC3, 0x00); priv->write_regpriv, SJA1000_ACCM0, 0xFF); priv->write_regpriv, SJA1000_ACCM1, 0xFF); priv->write_regpriv, SJA1000_ACCM2, 0xFF); priv->write_regpriv, SJA1000_ACCM3, 0xFF); priv->write_regpriv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL); } void mysja1000_startstruct sja1000_priv *priv) { printk"Enter the mysja1000_start "); /* leave reset mode */ if priv->can.state != CAN_STATE_STOPPED) myset_reset_modepriv); /* Initialize chip if uninitialized at this stage */ if !priv->read_regpriv, SJA1000_CDR) & CDR_PELICAN)) mychipset_initpriv); /* Clear error counters and error code capture */ priv->write_regpriv, SJA1000_TXERR, 0x0); priv->write_regpriv, SJA1000_RXERR, 0x0); priv->read_regpriv, SJA1000_ECC); /* leave reset mode */ myset_normal_modepriv); } int mysja1000_set_modestruct sja1000_priv *priv, enum can_mode mode) { switch mode) { case CAN_MODE_START: mysja1000_startpriv); // if netif_queue_stoppeddev)) // netif_wake_queuedev); break; default: return -EOPNOTSUPP; } return 0; } static u8 sp_read_reg8const struct sja1000_priv *priv, int reg) { return ioread8priv->reg_base + reg); } static void sp_write_reg8const struct sja1000_priv *priv, int reg, u8 val) { iowrite8val, priv->reg_base + reg); } int calc_com_addrint 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_rxstruct 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_skbdev, &cf); // if skb == NULL) // return; fi = priv->read_regpriv, SJA1000_FI); if fi & SJA1000_FI_FF) { printk"mysja1000_rx expand frame "); /* extended frame format EFF) */ dreg = SJA1000_EFF_BUF; id = priv->read_regpriv, SJA1000_ID1) << 21) | priv->read_regpriv, SJA1000_ID2) << 13) | priv->read_regpriv, SJA1000_ID3) << 5) | priv->read_regpriv, SJA1000_ID4) >> 3); id |= CAN_EFF_FLAG; } else { /* standard frame format SFF) */ dreg = SJA1000_SFF_BUF; id = priv->read_regpriv, SJA1000_ID1) << 3) | priv->read_regpriv, SJA1000_ID2) >> 5); } // cf->can_dlc = get_can_dlcfi & 0x0F); length_can = get_can_dlcfi & 0x0F); int curr_index = calc_com_addrid); 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_regpriv, dreg++); uart_insert_charcurr_port, 0, 0x02, ch, 0); curr_port->icount.tx++; // cf->data[i] = priv->read_regpriv, 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_cmdregpriv, CMD_RRB); } irqreturn_t mysja1000_interruptint 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_irqpriv); /* Shared interrupts and IRQ off? */ if priv->read_regpriv, SJA1000_IER) == IRQ_OFF) goto out; while isrc = priv->read_regpriv, SJA1000_IR)) && n < SJA1000_MAX_IRQ)) { status = priv->read_regpriv, SJA1000_SR); /* check for absent controller due to hw unplug */ // if status == 0xFF && sja1000_is_absentpriv)) // goto out; // if isrc & IRQ_WUI) // netdev_warndev, "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_skbdev, 0); } else { /* transmission complete */ // stats->tx_bytes += priv->read_regpriv, SJA1000_FI) & 0xf; // stats->tx_packets++; } // can_led_eventdev, CAN_LED_EVENT_TX); } if isrc & IRQ_RI) { /* receive interrupt */ while status & SR_RBS) { mysja1000_rxpriv); status = priv->read_regpriv, SJA1000_SR); /* check for absent controller */ // if status == 0xFF && sja1000_is_absentpriv)) // goto out; } } if isrc & IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { /* error interrupt */ // if sja1000_errdev, isrc, status)) // break; } n++; } out: if priv->post_irq) priv->post_irqpriv); // if n >= SJA1000_MAX_IRQ) // netdev_dbgdev, "%d messages handled in ISR", n); return n) ? IRQ_HANDLED : IRQ_NONE; } EXPORT_SYMBOL_GPLmysja1000_interrupt); int mysja1000_openstruct sja1000_priv *priv) { printk"enter mysja1000_open "); myset_reset_modepriv); /***********************open_candev)**********************/ // err = open_candevdev); 等效 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_errdev, "incorrect/missing data bit-timing "); printk"incorrect/missing data bit-timing "); return -EINVAL; } // mysja1000_set_modepriv, CAN_MODE_START); /*********************************************/ // 请求中断 待解决 // 第一个参数irq:申请的硬件中断号; // 第二个参数handler:是一个函数指针,向系统登记的中断处理函数,是一个回调函数,当中断发生时,系统调用这个函数,传入的参数包括中断设备 id,寄存器值。 // 第三个参数flags:指定了快速中断或中断共享等中断处理属性。 // 第四个参数devices:指定设备驱动程序的名称。 // 第五个参数dev_id:传入中断处理程序的参数,可以为NULL,在注册共享中断时,此参数不能为NULL,作为共享中断时的中断区别参数。 int err = request_irq14, mysja1000_interrupt, priv->irq_flags, "canserial8250", void *)priv); if!err) { printk"request_irq failed "); } mysja1000_startpriv); } int mysja1000_closestruct sja1000_priv *priv) { printk"mysja1000_close "); myset_reset_modepriv); if !priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) free_irq14, void *)priv); // close_candevdev); 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_xmitstruct sk_buff *skb, // struct sja1000_priv *priv) netdev_tx_t mysja1000_start_xmitstruct 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_skbdev, skb)) // return NETDEV_TX_OK; // netif_stop_queuedev); 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_regpriv, SJA1000_FI, fi); priv->write_regpriv, SJA1000_ID1, id & 0x1fe00000) >> 21); priv->write_regpriv, SJA1000_ID2, id & 0x001fe000) >> 13); priv->write_regpriv, SJA1000_ID3, id & 0x00001fe0) >> 5); priv->write_regpriv, SJA1000_ID4, id & 0x0000001f) << 3); } else { dreg = SJA1000_SFF_BUF; priv->write_regpriv, SJA1000_FI, fi); priv->write_regpriv, SJA1000_ID1, id & 0x000007f8) >> 3); priv->write_regpriv, SJA1000_ID2, id & 0x00000007) << 5); } for i = 0; i < dlc; i++) { printk"send data:%d ", cf->data[i]); priv->write_regpriv, dreg++, cf->data[i]); } // can_put_echo_skbskb, 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_cmdregpriv, cmd_reg_val); return NETDEV_TX_OK; } int sja1000_is_absentstruct sja1000_priv *priv) { printk"sja1000_is_absent "); return priv->read_regpriv, SJA1000_MOD) == 0xFF); } int myregister_sja1000devstruct sja1000_priv *priv) { int ret; printk"Enter myregister_sja1000dev "); // if !mysja1000_probe_chippriv)) // return -ENODEV; if priv->reg_base && sja1000_is_absentpriv)) { printk"probing failed "); return 0; } // dev->flags |= IFF_ECHO; we support local echo // dev->netdev_ops = &sja1000_netdev_ops; myset_reset_modepriv); mychipset_initpriv); // ret = register_candevdev); // if !ret) // devm_can_led_initdev); // return ret; } // probe 这一块没什么问题 int mytscan1_probestruct 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_sja1000devpriv); return 0; }
