/**************************************************************************************/
/*文件 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.cnblogs.com/woshiziyu/archive/2012/08/21/2649618.html

LINUX-S3C2440-SJA1000驱动程序-笔记相关推荐

  1. Linux USB鼠标驱动程序笔记 A

    关于这个驱动的源码,我看了几遍,每一次都有不同的感悟,只要自己本来就是菜鸟,慢慢领悟linux中包含的智慧... 本来一开始看的一本书,叫<Linux那些事>,但是太长了,实在看不下去,索 ...

  2. windows pxe 安装linux,菜鸟学Linux 第103篇笔记 pxe自动化安装linux

    菜鸟学Linux 第103篇笔记 pxe自动化安装linux 内容总览 linux的系统安装 kickstart文件的组成部分 DHCP (Dynamic Host Configuration Pro ...

  3. linux设备驱动读书笔记

    linux设备驱动读书笔记 设备驱动简介 机制:提供什么能力 策略:如何使用这些能力 在编写驱动时, 程序员应当编写内核代码来存取硬件, 但是不能强加特别的策略给用户, 因为不同的用户有不同的需求. ...

  4. linux设备驱动读书笔记(转)

    linux设备驱动读书笔记 设备驱动简介 机制:提供什么能力 策略:如何使用这些能力 在编写驱动时, 程序员应当编写内核代码来存取硬件, 但是不能强加特别的策略给用户, 因为不同的用户有不同的需求. ...

  5. 【学习札记NO.00004】Linux Kernel Pwn学习笔记 I:一切开始之前

    [学习札记NO.00004]Linux Kernel Pwn学习笔记 I:一切开始之前 [GITHUB BLOG ADDR](https://arttnba3.cn/2021/02/21/NOTE-0 ...

  6. 菜鸟学Linux 第044篇笔记 算法和私有CA

    菜鸟学Linux 第044篇笔记 算法和私有CA 证书吊销列表CRL(Certificate Revocation List ) 如何解决私钥丢失 PKI: Public Key Infrastruc ...

  7. Linux第二周学习笔记(7)

    Linux第二周学习笔记(7) 2.13 文档查看cat_more_less_head_tail (1). cat命令 cat命令:用于查看一个文件的内容并将其显示在屏幕上 cat-A命令:显示所有的 ...

  8. 菜鸟学Linux 第050篇笔记 dhcp

    菜鸟学Linux 第050篇笔记 dhcp DHCP (Dynamic Host Configuration Protocol) 早期bootp (boot protocol) lease Clien ...

  9. Linux第二周学习笔记(11)

    Linux第二周学习笔记(11) 2.17 隐藏权限lsattr_chattr chattr命令:是设置吟唱隐藏权限的命令,更改Linux文件系统上的文件属性. 参数说明: A:表示文件或目录的ati ...

最新文章

  1. js脚本 处理js注入
  2. There are no interfaces on which a capture can be done.
  3. 《学得少考得好》读书笔记
  4. 女朋友当众甩了我一巴掌,我扑上去......
  5. jvm jstat_使用jstat报告自定义JVM指标集
  6. 人工智能和机器学习的前世今生
  7. linux中文快捷键,Linux系统快捷键最全合集
  8. Purism释出Librem 5智能型手机新进展
  9. oracle数据库考试答题,Oracle数据库试题
  10. 本博客自排名1000到400的各项数据变化
  11. 昂达vi40精英版刷Linux,昂达Vi40精英版V1.0固件专业网友实测
  12. 《PMP学习笔记》1.3 五大过程组十大知识领域
  13. 全新版在线迅捷PDF转换器
  14. 【翻译】BKZ 2.0: Better Lattice Security Estimates 论文翻译
  15. Springboot启动流程分析(四):完成启动流程
  16. 上海理工大学854C语言真题,2018年上海理工大学医疗器械与食品院854C程序设计考研核心题库...
  17. 安装配置Windows AIK之生成Windows PE
  18. XMM SSE2浮点指令
  19. golang 读取Response Body 超时问题
  20. 百度语音教程完整版(附 音频文件下载地址)

热门文章

  1. HttpWebRequest 提示 “基础连接已关闭:发送时发生意外错误” 的解决方法
  2. HDU - 5172 GTY's gay friends
  3. python照片过人脸_python openCV实现摄像头获取人脸图片
  4. 世界最大的两个BT网站被迫下线 ExtraTorrent遭遇DDoS攻击
  5. Jin Ge Jin Qu hao - UVa 12563 dp背包
  6. Linux发展史及简介
  7. 318分组聚合,关联查询(多表连接查询)(连接查询),连接查询oracle写法,集合运算ld
  8. STM32串口通信配置(USART1+USART2+USART3+UART4)
  9. 中文情感分析 (Sentiment Analysis) 的难点在哪?现在做得比较好的有哪几家?
  10. 极兔、百世被罚后:每单涨价 4、5 毛