zoukankan      html  css  js  c++  java
  • LINUXS3C2440SJA1000驱动程序笔记

    /**************************************************************************************/
    /*文件 program_22_1.c                                         */
    /*SJA1000驱动程序                                   */
    /*************************************************************************************/
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include <linux/ioport.h>
    #include <linux/poll.h>
    #include <linux/delay.h>
    #include <asm/hardware.h>
     /*这里包含了所有寄存器地址映射方式,有了这个头文件,CPU所有的寄存器都可以通过宏来实现 */
    
    #include <asm/arch/cpu_s3c2440.h>
    #include <linux/interrupt.h>
    #include "candriver.h"    /*这个头文件这里没有给出,包含驱动的私有变量和方法。*/
    #define FAIL 0
    #define SUCCESS 1
    #define DEVICE_NAME "SJACAN"
    #define MAX_NR_FRAMES    100     /*允许接受的最大帧数目,据此定义缓冲的大小*/
    
    unsigned char Receive(unsigned char *RCdata);
    void Transmit(unsigned char *TXdata);
    
    
    
    int log_flag = 1; // 0 -- stop buffer CAN frames. 1 -- start buffer CAN frames.
    
    struct rec
    {
    unsigned char databuf[13 * MAX_NR_FRAMES];    /*每一帧的数据是13个*/
    int start,end;    /*0,1,2,...9*/
    } rd_buf;
    
    void init_rd_buf()
    {
    rd_buf.start = 0;
    rd_buf.end = 0;
    }
    
    int is_empty_rd_buf()
    {
    return (rd_buf.start == rd_buf.end);  /*判断第一帧个最后一帧的位置是否相同,是则为空*/
    }
    
    int is_full_rd_buf()
    {
    return (rd_buf.start == (rd_buf.end+1) % MAX_NR_FRAMES); /*判断接收缓冲是否满*/
    }
    
    void out_rd_buf(unsigned char *buf)
    {
    if(is_empty_rd_buf())
    return;           /*如果是空的,返回*/
    memcpy(buf, &rd_buf.databuf[rd_buf.start*13],13); 
    /*从rd_buf.databuf[rd_buf.start*13]开始读取数据,一次读取一帧=13个字节 */
    rd_buf.start = ++rd_buf.start % MAX_NR_FRAMES;  /*改变rd_buf.start的位置,指向下一帧*/
    }
    
    void in_rd_buf(unsigned char *buf)
    {
    if(is_full_rd_buf())
    return;   /*如果满,返回*/
    memcpy(&rd_buf.databuf[rd_buf.end*13],buf,13); 
        /*从rd_buf.databuf[rd_buf.end*13]开始写数据,一次写一帧=13字节*/
    rd_buf.end = ++rd_buf.end % MAX_NR_FRAMES;  /*改变 rd_buf.end的位置,指向下一帧*/
    }
    
    
    
    int intialize_can1(void)
    {
    CAN_STRUCT can1;
    UI i;
    
    //初始化can1
    canReset();    /*因为SJA1000的地址数据复用,所以用一个CPLD对其时序做一个逻辑转换*/
    //对SJA1000进行硬件重置  
    
    for(i=0;i<4;i++)
    {
    can1.acc_code[i]=0x00;  /*设置acc掩码*/
    can1.acc_mask[i]=0xff;
    }
    can1.bt0=0x03;  /*波特率*/
    can1.bt1=0x1c;
    
    if(canConfig(can1)==FAIL)  /*如果设置错误,返回-1*/
    {
    return -1;
    }
    
    //can1开始运行
    canNormalRun();
    
    //向寄存器CMR写入0x04就能清除接收缓冲中的数据 
    pokeb(SEG1,CMR,0x04);                  /*release receive buffer*/
    
    peekb(SEG1,ALC);
    peekb(SEG1,ECC);
    
    return 0;
    }
    
    
    static irqreturn_t  sja1000_can_irq(int irq, void *dev_id, struct pt_regs *regs)
    {
    unsigned char buf[13];
    int intrkind,s;
    /*读中断寄存器状态*/
    intrkind=peekb(SEG1,IR);//read the interrupt status
    printk("can1 get data!\n");   
    if((intrkind & 0x01) == 0)/*not receive interrupt*/ /*没有接收中断产生*/
    {
    
    goto out;
    }
    
    Receive(buf);  
    
    if(log_flag)
    in_rd_buf(buf);    //buffer this frame  /*将这一帧数据复制到接收缓冲中*/
    peekb(SEG1,IR);
    pokeb(SEG1,CMR,0x04);                   /*release receive buffer*/   /*释放接收缓冲*/
    s=peekb(SEG1,ALC);
    s=peekb(SEG1,ECC);
    return IRQ_HANDLED;
    
    out:
    pokeb(SEG1,CMR,0x04); //clear sja receive buffer in order to clear it's INT signal
    /*清除接收缓冲以便清除接手中断*/
    return IRQ_NONE;
    
    }
    
    
    
    /*------------------------------------------------------------*/
    unsigned char Receive(unsigned char *RCdata)
    {
    int i=16;  /*接收缓冲地址是从16开始的*/
    int j=0;
    unsigned char sr =peekb(SEG1,SR);    /*读状态寄存器*/
    for(;j<13;i++,j++){
    RCdata[j] = peekb(SEG1,i);     /*复制13个数据到内存*/
    }
    return sr;   
    }
    
    void Transmit(unsigned char *TXdata)
    {
    int i=16; /*发送缓冲的地址从16开始*/
    int j=0;
    int MAXWAIT=1000;  /*最大等待时间,总线可能忙*/
    do{
    // printk("xxxxxxxxxxxx\n");
    MAXWAIT--;
    if (MAXWAIT==0)
    {
    printk("send fail!\n");
    return;}
    }while( !(peekb(SEG1,SR)&0x04) ); /*读出状态寄存器的值,是否可以发送*/
    
    for(;j<13;i++,j++){
    pokeb(SEG1,i,TXdata[j]);   /*如果可以发,就把数据从内存复制到SJA1000的发送缓冲中去*/
    }
    pokeb(SEG1,CMR,0x01);        /*写0x01给CMR,发送*/
    }
    
    
    
    
    
    
    
    static ssize_t can_read(struct file *filep,char *buffer,size_t length,loff_t *ppos)
    {
    int total = 0;
    while(1){
    if(total >= length)   /*如果给定长度小于0,或者已将给定长度的数据读出去,就跳出*/
    break;
    
    if(is_empty_rd_buf())  /*如果接收缓冲是空,跳出*/
    break;
    
    out_rd_buf(buffer+total);  /*读出接收缓冲里的数据*/
    
    total+=13;  /*每完成一次+13*/
    }
    return total;  /*返回总的读出数据长度*/
    }
    
    
    static ssize_t can_write(struct file *filep,const char *buffer,size_t length, loff_t *ppos)
    {
    int total = 0,i;
    unsigned char TXdata[13];  /*临时数组,用来存放发送数据*/
    
    printk("the data to be sended by can1 is :\n");
    for(i=0;i<13;i++){
    printk("[%d]=%x ",i,buffer[i]);
    }
    printk("\n");
    
    while(total+13 <= length){
    memcpy(TXdata,buffer+total,13);  /*将待发送数据复制到临时数组中*/
    Transmit(TXdata);  /*发送*/
    total += 13;
    }
    return total;
    }
    
    /*------------------------------------------------------------------*/
    
    static int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
    {
    int error, n, rc = 0;
    struct sja_reg sja_reg_data;// = 0;
    switch (cmd) {
    
    case SJA_IOCTL_WRITE:   
    copy_from_user(&sja_reg_data,(void *)arg,sizeof(struct sja_reg));
    printk("write_sja_reg_addr=%x\n",sja_reg_data.sja_reg_addr);
    printk("write_sja_reg_value=%x\n",sja_reg_data.sja_reg_value);
    pokeb(SEG1,sja_reg_data.sja_reg_addr, sja_reg_data.sja_reg_value);
    break;
    case SJA_IOCTL_READ:
    printk("enter read\n");   
    copy_from_user(&sja_reg_data,(void *)arg,sizeof(struct sja_reg));
    printk("sja_reg_addr=%x\n",sja_reg_data.sja_reg_addr);
    sja_reg_data.sja_reg_value = peekb(SEG1,sja_reg_data.sja_reg_addr);
    printk("sja_reg_value=%x\n",sja_reg_data.sja_reg_value);
    copy_to_user((void *)arg,&sja_reg_data,sizeof(struct sja_reg));
    break;
    default:
    rc = -EINVAL;
    break;
    }
    
    return rc;
    }
    
    
    static int can_open(struct inode *inode, struct file *file)
    {
    
    return 0;
    }
    
    
    static int can_release(struct inode *inode, struct file *file)
    {
    
    return 0;
    }
    
    
    
    struct file_operations fops = {
    owner:        THIS_MODULE,
    open:        can_open,
    read:        can_read,
    write:        can_write,
    ioctl:            can_ioctl,
    release:        can_release,  /* a.k.a. close */
    };
    
    static void s3c2440_GPIO_init(void)
    {
    /*初始化CPU的GPIO口*/
    Set_external_irq(IRQ_CAN,EXT_RISING_EDGE,GPIO_PULLUP_DIS);
    /*分配外部中断6,上升沿有效,下拉有效*/
    delay(1000);
    }
    
    /*----------------init for module driver-----------------*/
    int __init sja1000_init(void)
    {
    int a,ret;
    
    /*映射CAN的SJA1000物理地址*/
    SEG1=ioremap((0x14000000+(0xDA000<<2)),128);
    /*硬件RESET的地址*/
    SEG3=SEG1+(0x101<<2);
    
    /*初始化CAN寄存器*/
    a=intialize_can1();
    
    /*是否初始化成功,从打印的消息可以看出来*/ 
    if(a==0){
    
    s3c2440_GPIO_init();
    
    /*申请中断号*/   
    ret=request_irq(IRQ_GPIO(92),&sja1000_can_irq,SA_INTERRUPT,"can1_irq",NULL);
    if(ret < 0)
    {
    printk ("%s device failed with %d\n","Sorry, registering the IRQ", ret);
    return ret; /*失败就退出*/
    }
    delay(1000);
    /*申请设备号*/  
    ret = register_chrdev(126, DEVICE_NAME, &fops);
    if (ret < 0)
    {
    printk ("%s device failed with %d\n","Sorry, registering the character", ret);
    return ret;
    }
    delay(1000);
    
    
    printk("can1_sja1000 driver init ok!\n");
    
    
    
    
    
    return 0;
    }
    else
    {
    printk("can1_sja1000 driver init fail!\n");
    return -1;
    }
    
    }
    
    /* Cleanup - undid whatever init_module did */
    void __exit sja1000_exit(void)
    {
    int ret;
    /*再次重置CAN*/
    canReset();
    /*注销中断号*/
    free_irq(IRQ_GPIO(92), NULL);
    /*注销映射地址*/
    iounmap(SEG1);
    /*注销设备号*/      
    ret = unregister_chrdev(126, DEVICE_NAME);
    if (ret < 0)
    printk("Error in unregister_chrdev: %d\n", ret);
    }
    
    module_init(sja1000_init);
    module_exit(sja1000_exit);
    

    作者:子鱼
    出处:https://www.yiboard.com
    本文版权归作者和一板网电子技术论坛共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    js 仿 asp中的 asc 和 chr 函数的代码
    escape,encodeURI,encodeURIComponent
    从项目从SVN上check下来,用idea打开后,idea没有SVN的工具栏解决方法
    idea中导入SVN的项目时,连接失败,报“Cannot run program "svn"
    spring基础----事件(Applicaition Event)
    idea在导入项目时遇到的问题
    Spring基础---bean的初始化和销毁
    spring基础----EL和资源调用
    spring基础----Bean的Scope
    面试题-------------js三种信息框
  • 原文地址:https://www.cnblogs.com/woshiziyu/p/2649618.html
Copyright © 2011-2022 走看看