Linux主机驱动和外设驱动分离思想
SPI驱动总线架构:SPI核心层(x),SPI控制器驱动层(x),SPI设备驱动层(√)
2 Linux SPI驱动总体架构 在2.6的linux内核中,SPI的驱动架构可以分为如下三个层次:SPI 核心层、SPI控制器驱动层和SPI设备驱动层。
Linux 中SPI驱动代码位于drivers/spi目录。
2.1 SPI核心层 SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。
Linux中,SPI核心层的代码位于driver/spi/ spi.c。由于该层是平台无关层,本文将不再叙述,有兴趣可以查阅相关资料。
2.2 SPI控制器驱动层 SPI控制器驱动层,每种处理器平台都有自己的控制器驱动,属于平台移植相关层。它的职责是为系统中每条SPI总线实现相应的读写方法。在物理上,每个SPI控制器可以连接若干个SPI从设备。
在系统开机时,SPI控制器驱动被首先装载。一个控制器驱动用于支持一条特定的SPI总线的读写。一个控制器驱动可以用数据结构struct spi_master来描述。
3.SPI相关的数据结构
3.1 struct spi_master 用于描述一个SPI控制器
//在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下:
struct spi_master {
struct device dev;
s16 bus_num;
u16 num_chipselect;
int (*setup)(struct spi_device *spi);
int (*transfer)(struct spi_device *spi, struct spi_message *mesg);
void (*cleanup)(struct spi_device *spi);
};
bus_num为该控制器对应的SPI总线号。
num_chipselect 控制器支持的片选数量,即能支持多少个spi设备
setup函数是设置SPI总线的模式,时钟等的初始化函数, 针对设备设置SPI的工作时钟及数据传输模式等。在spi_add_device函数中调用。
transfer函数是实现SPI总线读写方法的函数。实现数据的双向传输,可能会睡眠
cleanup 注销的时候调用
3.2 SPI设备驱动层
SPI设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口。
SPI设备驱动层可以用两个模块来描述,struct spi_driver和struct spi_device。
相关的数据结构如下:
struct spi_driver 用来描述一个SPI设备的驱动信息
struct spi_driver {
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
int (*resume)(struct spi_device *spi);
struct device_driver driver;
};
Driver是为device服务的,spi_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定,probe函数用于驱动和设备匹配时被调用。从上面的结构体注释中我们可以知道,SPI的通信是通过消息队列机制,而不是像I2C那样通过与从设备进行对话的方式。
struct spi_device 用来描述一个SPI总线上的从设备
通常来说spi_device对应着SPI总线上某个特定的slave。并且spi_device封装了一个spi_master结构体。
spi_device结构体包含了私有的特定的slave设备特性,包括它最大的频率,片选那个,输入输出模式等等
struct spi_device {
struct device dev;
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 mode;
u8 bits_per_word;
int irq;
void *controller_state;
void *controller_data;
char modalias[32];
};
4 spi_device以下一系列的操作是在platform板文件中完成!
spi_device的板信息用spi_board_info结构体来描述:
spi_board_info参数
.modalias = "rc522", //初始化设备的名称
.platform_data = NULL,
.max_speed_hz = 10*1000*1000, //初始化传输速率
.bus_num = 2, //控制器编号
.chip_select = 0, //控制器片选的编号
.mode = SPI_MODE_0, //spi的模式 CPOL=0, CPHA=0 此处选择具体数据传输模式
.controller_data = &spi2_csi[0], //片选IO的信息
spi2_board_info设备描述结构体,设备注册函数spi_register_board_info
而这个info在init函数调用的时候会初始化:
spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));//注册spi_board_info。
这个代码会把spi_board_info注册到链表board_list上。
spi_device封装了一个spi_master结构体,事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,找到挂接在它上面的spi设备,然后创建并注册spi_device。
至此spi_device就构建并注册完成了!
5 spi_driver的构建与注册
driver有几个重要的结构体:spi_driver、spi_transfer、spi_message
driver有几个重要的函数 :spi_message_init、spi_message_add_tail、spi_sync
//spi_driver的构建
static struct spi_driver m25p80_driver = {
.driver = {
.name ="m25p80",
.bus =&spi_bus_type,
.owner = THIS_MODULE,
},
.probe = m25p_probe,
.remove =__devexit_p(m25p_remove),
};
//spidriver的注册
spi_register_driver(&m25p80_driver);
在有匹配的spi_device时,会调用m25p_probe
probe里完成了spi_transfer、spi_message的构建;
spi_message_init、spi_message_add_tail、spi_sync、spi_write_then_read函数的调用
在SPI总线上是通过封装一系列的spi_transfer到一个spi_message中,然后将spi_message提交到SPI子系统去。
下面是spi_transfer结构:
struct spi_transfer {
const void*tx_buf; //驱动提供的发送缓冲区dma,
void *rx_buf; //接收缓冲区
unsigned len; //长度一般是8位
dma_addr_ttx_dma; //发送dma,controller使用
dma_addr_t rx_dma; //接收dma
unsigned cs_change:1; //片选位
u8 bits_per_word; //每字长度
u16 delay_usecs; //延迟
u32 speed_hz; //速度
struct list_headtransfer_list; //transfer 链表
};
在spi_transfer中时常更改的域也许只有len,tx_buf和rx_buf。剩下的当以0来初始化。
单个spi_transfer可表示一次读,一次写或者是一次读写。在SPIcontroller驱动下,所有操作常是全双工的。向spi_transfer中rx_buf传递一个NULL,这就是一次只写操作,会丢弃MISO线上的数据。同样向tx_buf传递一个NULL,这就是一次只读操作了。spi_transfer中len域代表(已经多少字节数据流过总线了)howmany bytes to clock the bus。
spi_message结构:
struct spi_message {
struct list_head transfers;
struct spi_device *spi;
unsigned is_dma_mapped:1;
void (*complete)(void*context);
void *context;
unsigned actual_length;
int status;
struct list_head queue;
void *state;
};
transfer这个spi_message所包含有的spi_transfer链表头。
is_dma_mappedspi_transfer中tx_dma和rx_dma是否已经mapped。
complete回调函数
context 提供给complete的可选参数
actual_lengthspi_message已经传输了的字节数
status 出错与否,错误时返回errorcode
queue 和state 供controller驱动内部使用
在每次使用spi_message可以使用函数void spi_message_init(structspi_message *m);来初始化。
向spi_message添加transfers可以使用spi_message_add_tail()函数:
void spi_message_add_tail(structspi_transfer *t, struct spi_message *m);
一旦你准备好了spi_message,就可以使用spi_async()来向SPI系统提交了:
int spi_async(struct spi_device *spi,struct spi_message *message);
因为是异步的,一提交就立马返回了,这也就是说需要同步机制(complete就是了)。他确保不会睡眠,可安全的在中断handler或其他不可休眠的代码中调用。稍后会念念他的好的。
使用spi_async()需要注意的是,在complete()未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。
使用完成回调机制稍显复杂,可以使用SPI系统提供的另一个同步版本:spi_sync():
int spi_sync(struct spi_device *spi,struct spi_message *message);
因为是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()在drivers/spi/spi.c中实现,其调用了spi_async(),并休眠直至complete返回。
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/ioctl.h>
4 #include <linux/fs.h>
5 #include <linux/device.h>
6 #include <linux/err.h>
7 #include <linux/list.h>
8 #include <linux/errno.h>
9 #include <linux/mutex.h>
10 #include <linux/slab.h>
11 #include <linux/compat.h>
12 #include <linux/spi/spi.h>
13 #include <linux/spi/spidev.h>
14 #include <asm/uaccess.h>
15 #include <linux/gpio.h>
16 #include <mach/gpio.h>
17 #include <plat/gpio-cfg.h>
18 #include <linux/delay.h>
19 #include <linux/miscdevice.h>
20
21 struct spi_device *my_spi;
22
23 #define RC522_RESET_PIN EXYNOS4_GPK1(0)
24
25 void my_rc522_reset() // 驱动初始化 (IO部分)
26 {
27 //printk("************************ %s\n", __FUNCTION__);
28 if(gpio_request_one(RC522_RESET_PIN, GPIOF_OUT_INIT_HIGH, "RC522_RESET"))
29 pr_err("failed to request GPK1_0 for RC522 reset control\n");
30
31 s3c_gpio_setpull(RC522_RESET_PIN, S3C_GPIO_PULL_UP);
32 gpio_set_value(RC522_RESET_PIN, 0);
33
34 mdelay(5);
35
36 gpio_set_value(RC522_RESET_PIN, 1);
37 gpio_free(RC522_RESET_PIN);
38 }
39
40 //static ssize_t rc522_write(unsigned char *buffer, int len)
41 static ssize_t rc522_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
42 {
43 int status;
44 unsigned char tx_buf[2];
45
46 status = copy_from_user(tx_buf,buf,count);
47
48 struct spi_transfer t = {
49 .tx_buf = tx_buf,
50 .len = count,
51 };
52 struct spi_message m;
53 spi_message_init(&m);
54 spi_message_add_tail(&t, &m);
55 DECLARE_COMPLETION_ONSTACK(done);
56 m.complete = complete;
57 m.context = &done;
58
59 printk("spi_async send begin!\n");
60 status = spi_async(my_spi,&m);
61 if(status == 0){
62 wait_for_completion(&done);
63 status = m.status;
64 if (status == 0)
65 status = m.actual_length;
66 }
67 return status;
68 }
69
70
71 //static ssize_t rc522_read(unsigned char *buffer, int len)
72 static ssize_t rc522_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
73 {
74 // 驱动读函数的底层部分
75 int status;
76 unsigned char *rx_buf;
77
78 struct spi_transfer t = {
79 .rx_buf = &rx_buf,
80 .len = count,
81 };
82 struct spi_message m;
83 spi_message_init(&m);//初始化一个spi_message/一个不可打断的SPI传输过程:CS=0,传数据,cs=1/
84 spi_message_add_tail(&t, &m);//spi_transfer是spi上传输的单方向一个或者多个字节
85 DECLARE_COMPLETION_ONSTACK(done);////声明并初始化一个完成量done 启动传输并等待完成
86 m.complete = complete; //回调函数
87 m.context = &done; //提供给complete的可选参数
88
89 printk("spi_async read begin!\n");
90 status = spi_async(my_spi,&m); //向SPI系统提交 spi_message
91 if(status == 0){
92 wait_for_completion(&done);//这个函数进行一个不可打断的等待. 如果你的代码调用 wait_for_completion 并且
93 //没有人完成这个任务, 结果会是一个不可杀死的进程
94 status = m.status;
95 if (status == 0)
96 status = m.actual_length;
97 }
98
99 status = copy_to_user(buf,&rx_buf,status);
100
101 return status;
102 }
103
104 int rc522_open(struct inode *inode,struct file *filp)
105 {
106 return 0;
107 }
108
109
110
111 static struct file_operations rc522_ops = { //驱动对应的结构体
112 .owner = THIS_MODULE,
113 .open = rc522_open,
114 .read = rc522_read,
115 .write = rc522_write,
116 };
117
118 static struct miscdevice rc522_dev = { // rc522作为一个杂项设备存在
119 .minor = MISC_DYNAMIC_MINOR,
120 .fops = &rc522_ops,
121 .name = "rc522",
122 };
123
124 static int __devinit my_rc522_probe(struct spi_device *spi) // 说明驱动名 == 设备名,进入到probe驱动函数
125 {
126
127 printk("my_rc522_probe!\n");
128
129 /* reset */
130 my_rc522_reset();
131 my_spi = spi;
132
133 misc_register(&rc522_dev);
134
135 return 0;
136 }
137
138 static int __devexit my_rc522_remove(struct spi_device *spi)
139 {
140 printk("my_rc522_remove!\n");
141 misc_deregister(&rc522_dev);
142 return 0;
143 }
144
145 static struct spi_driver my_rc522_spi_driver = { // 用来描述一个SPI设备的驱动信息
146 .driver = {
147 .name = "my_rc522",
148 .owner = THIS_MODULE,
149 },
150 .probe = my_rc522_probe,
151 .remove = __devexit_p(my_rc522_remove),
152
153 /* NOTE: suspend/resume methods are not necessary here.
154 * We don't do anything except pass the requests to/from
155 * the underlying controller. The refrigerator handles
156 * most issues; the controller driver handles the rest.
157 */
158 };
159
160
161 static int __init my_rc522_init(void)
162 {
163 spi_register_driver(&my_rc522_spi_driver); // 注册SPI驱动
164 return 0;
165 }
166
167 static void __exit my_rc522_exit(void)
168 {
169 spi_unregister_driver(&my_rc522_spi_driver); // 卸载驱动
170 }
171
172 module_exit(my_rc522_exit);
173 module_init(my_rc522_init);
174
175
176 MODULE_AUTHOR("topeet: rty");
177 MODULE_LICENSE("GPL");
myrc522.c
1 /*
2 * SPI testing utility (using spidev driver)
3 *
4 * Copyright (c) 2007 MontaVista Software, Inc.
5 * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License.
10 *
11 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
12 */
13
14 #include <stdint.h>
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <getopt.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #include <linux/types.h>
22
23 #include "spidev.h"
24 #include "spidev_test.h"
25
26 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
27
28 static void pabort(const char *s)
29 {
30 perror(s);
31
32 abort();
33 }
34
35 static const char *device = "/dev/rc522";
36 static uint8_t mode;
37 static uint8_t bits = 8;
38 static uint32_t speed = 400 * 1000;//500000;
39 static uint16_t delay;
40
41 int g_SPI_Fd = 0;
42
43 unsigned char UID[5], Temp[4];
44
45 /*******************************************
46 函数名称:tochar
47 功 能:处理16进制函数
48 参 数:id
49 返回值 :无
50 ********************************************/
51 #if 0
52 void tochar(unsigned char id)
53 {
54 switch(id)
55 {
56 case 0x00:printf("00");break;
57 case 0x01:printf("01");break;
58 case 0x02:printf("02");break;
59 case 0x03:printf("03");break;
60 case 0x04:printf("04");break;
61 case 0x05:printf("05");break;
62 case 0x06:printf("06");break;
63 case 0x07:printf("07");break;
64 case 0x08:printf("08");break;
65 case 0x09:printf("09");break;
66 case 0x0a:printf("0a");break;
67 case 0x0b:printf("0b");break;
68 case 0x0c:printf("0c");break;
69 case 0x0d:printf("0d");break;
70 case 0x0e:printf("0e");break;
71 case 0x0f:printf("0f");break;
72 case 0x10:printf("10");break;
73 case 0x11:printf("11");break;
74 case 0x12:printf("12");break;
75 case 0x13:printf("13");break;
76 case 0x14:printf("14");break;
77 case 0x15:printf("15");break;
78 case 0x16:printf("16");break;
79 case 0x17:printf("17");break;
80 case 0x18:printf("18");break;
81 case 0x19:printf("19");break;
82 case 0x1a:printf("1a");break;
83 case 0x1b:printf("1b");break;
84 case 0x1c:printf("1c");break;
85 case 0x1d:printf("1d");break;
86 case 0x1e:printf("1e");break;
87 case 0x1f:printf("1f");break;
88 case 0x20:printf("20");break;
89 case 0x21:printf("21");break;
90 case 0x22:printf("22");break;
91 case 0x23:printf("23");break;
92 case 0x24:printf("24");break;
93 case 0x25:printf("25");break;
94 case 0x26:printf("26");break;
95 case 0x27:printf("27");break;
96 case 0x28:printf("28");break;
97 case 0x29:printf("29");break;
98 case 0x2a:printf("2a");break;
99 case 0x2b:printf("2b");break;
100 case 0x2c:printf("2c");break;
101 case 0x2d:printf("2d");break;
102 case 0x2e:printf("2e");break;
103 case 0x2f:printf("2f");break;
104 case 0x30:printf("30");break;
105 case 0x31:printf("31");break;
106 case 0x32:printf("32");break;
107 case 0x33:printf("33");break;
108 case 0x34:printf("34");break;
109 case 0x35:printf("35");break;
110 case 0x36:printf("36");break;
111 case 0x37:printf("37");break;
112 case 0x38:printf("38");break;
113 case 0x39:printf("39");break;
114 case 0x3a:printf("3a");break;
115 case 0x3b:printf("3b");break;
116 case 0x3c:printf("3c");break;
117 case 0x3d:printf("3d");break;
118 case 0x3e:printf("3e");break;
119 case 0x3f:printf("3f");break;
120 case 0x40:printf("40");break;
121 case 0x41:printf("41");break;
122 case 0x42:printf("42");break;
123 case 0x43:printf("43");break;
124 case 0x44:printf("44");break;
125 case 0x45:printf("45");break;
126 case 0x46:printf("46");break;
127 case 0x47:printf("47");break;
128 case 0x48:printf("48");break;
129 case 0x49:printf("49");break;
130 case 0x4a:printf("4a");break;
131 case 0x4b:printf("4b");break;
132 case 0x4c:printf("4c");break;
133 case 0x4d:printf("4d");break;
134 case 0x4e:printf("4e");break;
135 case 0x4f:printf("4f");break;
136 case 0x50:printf("50");break;
137 case 0x51:printf("51");break;
138 case 0x52:printf("52");break;
139 case 0x53:printf("53");break;
140 case 0x54:printf("54");break;
141 case 0x55:printf("55");break;
142 case 0x56:printf("56");break;
143 case 0x57:printf("57");break;
144 case 0x58:printf("58");break;
145 case 0x59:printf("59");break;
146 case 0x5a:printf("5a");break;
147 case 0x5b:printf("5b");break;
148 case 0x5c:printf("5c");break;
149 case 0x5d:printf("5d");break;
150 case 0x5e:printf("5e");break;
151 case 0x5f:printf("5f");break;
152 case 0x60:printf("60");break;
153 case 0x61:printf("61");break;
154 case 0x62:printf("62");break;
155 case 0x63:printf("63");break;
156 case 0x64:printf("64");break;
157 case 0x65:printf("65");break;
158 case 0x66:printf("66");break;
159 case 0x67:printf("67");break;
160 case 0x68:printf("68");break;
161 case 0x69:printf("69");break;
162 case 0x6a:printf("6a");break;
163 case 0x6b:printf("6b");break;
164 case 0x6c:printf("6c");break;
165 case 0x6d:printf("6d");break;
166 case 0x6e:printf("6e");break;
167 case 0x6f:printf("6f");break;
168 case 0x70:printf("70");break;
169 case 0x71:printf("71");break;
170 case 0x72:printf("72");break;
171 case 0x73:printf("73");break;
172 case 0x74:printf("74");break;
173 case 0x75:printf("75");break;
174 case 0x76:printf("76");break;
175 case 0x77:printf("77");break;
176 case 0x78:printf("78");break;
177 case 0x79:printf("79");break;
178 case 0x7a:printf("7a");break;
179 case 0x7b:printf("7b");break;
180 case 0x7c:printf("7c");break;
181 case 0x7d:printf("7d");break;
182 case 0x7e:printf("7e");break;
183 case 0x7f:printf("7f");break;
184 case 0x80:printf("80");break;
185 case 0x81:printf("81");break;
186 case 0x82:printf("82");break;
187 case 0x83:printf("83");break;
188 case 0x84:printf("84");break;
189 case 0x85:printf("85");break;
190 case 0x86:printf("86");break;
191 case 0x87:printf("87");break;
192 case 0x88:printf("88");break;
193 case 0x89:printf("89");break;
194 case 0x8a:printf("8a");break;
195 case 0x8b:printf("8b");break;
196 case 0x8c:printf("8c");break;
197 case 0x8d:printf("8d");break;
198 case 0x8e:printf("8e");break;
199 case 0x8f:printf("8f");break;
200 case 0x90:printf("90");break;
201 case 0x91:printf("91");break;
202 case 0x92:printf("92");break;
203 case 0x93:printf("93");break;
204 case 0x94:printf("94");break;
205 case 0x95:printf("95");break;
206 case 0x96:printf("96");break;
207 case 0x97:printf("97");break;
208 case 0x98:printf("98");break;
209 case 0x99:printf("99");break;
210 case 0x9a:printf("9a");break;
211 case 0x9b:printf("9b");break;
212 case 0x9c:printf("9c");break;
213 case 0x9d:printf("9d");break;
214 case 0x9e:printf("9e");break;
215 case 0x9f:printf("9f");break;
216 case 0xa0:printf("a0");break;
217 case 0xa1:printf("a1");break;
218 case 0xa2:printf("a2");break;
219 case 0xa3:printf("a3");break;
220 case 0xa4:printf("a4");break;
221 case 0xa5:printf("a5");break;
222 case 0xa6:printf("a6");break;
223 case 0xa7:printf("a7");break;
224 case 0xa8:printf("a8");break;
225 case 0xa9:printf("a9");break;
226 case 0xaa:printf("aa");break;
227 case 0xab:printf("ab");break;
228 case 0xac:printf("ac");break;
229 case 0xad:printf("ad");break;
230 case 0xae:printf("ae");break;
231 case 0xaf:printf("af");break;
232 case 0xb0:printf("b0");break;
233 case 0xb1:printf("b1");break;
234 case 0xb2:printf("b2");break;
235 case 0xb3:printf("b3");break;
236 case 0xb4:printf("b4");break;
237 case 0xb5:printf("b5");break;
238 case 0xb6:printf("b6");break;
239 case 0xb7:printf("b7");break;
240 case 0xb8:printf("b8");break;
241 case 0xb9:printf("b9");break;
242 case 0xba:printf("ba");break;
243 case 0xbb:printf("bb");break;
244 case 0xbc:printf("bc");break;
245 case 0xbd:printf("bd");break;
246 case 0xbe:printf("be");break;
247 case 0xbf:printf("bf");break;
248 case 0xc0:printf("c0");break;
249 case 0xc1:printf("c1");break;
250 case 0xc2:printf("c2");break;
251 case 0xc3:printf("c3");break;
252 case 0xc4:printf("c4");break;
253 case 0xc5:printf("c5");break;
254 case 0xc6:printf("c6");break;
255 case 0xc7:printf("c7");break;
256 case 0xc8:printf("c8");break;
257 case 0xc9:printf("c9");break;
258 case 0xca:printf("ca");break;
259 case 0xcb:printf("cb");break;
260 case 0xcc:printf("cc");break;
261 case 0xcd:printf("cd");break;
262 case 0xce:printf("ce");break;
263 case 0xcf:printf("cf");break;
264 case 0xd0:printf("d0");break;
265 case 0xd1:printf("d1");break;
266 case 0xd2:printf("d2");break;
267 case 0xd3:printf("d3");break;
268 case 0xd4:printf("d4");break;
269 case 0xd5:printf("d5");break;
270 case 0xd6:printf("d6");break;
271 case 0xd7:printf("d7");break;
272 case 0xd8:printf("d8");break;
273 case 0xd9:printf("d9");break;
274 case 0xda:printf("da");break;
275 case 0xdb:printf("db");break;
276 case 0xdc:printf("dc");break;
277 case 0xdd:printf("dd");break;
278 case 0xde:printf("de");break;
279 case 0xdf:printf("df");break;
280 case 0xe0:printf("e0");break;
281 case 0xe1:printf("e1");break;
282 case 0xe2:printf("e2");break;
283 case 0xe3:printf("e3");break;
284 case 0xe4:printf("e4");break;
285 case 0xe5:printf("e5");break;
286 case 0xe6:printf("e6");break;
287 case 0xe7:printf("e7");break;
288 case 0xe8:printf("e8");break;
289 case 0xe9:printf("e9");break;
290 case 0xea:printf("ea");break;
291 case 0xeb:printf("eb");break;
292 case 0xec:printf("ec");break;
293 case 0xed:printf("ed");break;
294 case 0xee:printf("ee");break;
295 case 0xef:printf("ef");break;
296 case 0xf0:printf("f0");break;
297 case 0xf1:printf("f1");break;
298 case 0xf2:printf("f2");break;
299 case 0xf3:printf("f3");break;
300 case 0xf4:printf("f4");break;
301 case 0xf5:printf("f5");break;
302 case 0xf6:printf("f6");break;
303 case 0xf7:printf("f7");break;
304 case 0xf8:printf("f8");break;
305 case 0xf9:printf("f9");break;
306 case 0xfa:printf("fa");break;
307 case 0xfb:printf("fb");break;
308 case 0xfc:printf("fc");break;
309 case 0xfd:printf("fd");break;
310 case 0xfe:printf("fe");break;
311 case 0xff:printf("ff");break;
312 default:
313 ;
314 }
315 }
316 #endif
317
318 int WriteRawRC(int addr, int data) //向RC522 传数据
319 {
320 int ret;
321 int fd = g_SPI_Fd;
322 unsigned char TxBuf[2];
323
324 //bit7:MSB=0,bit6~1:addr,bit0:RFU=0
325 TxBuf[0] = ((unsigned char)addr << 1)&0x7E;
326 //TxBuf[0] &= 0x7E;
327
328 TxBuf[1] = (unsigned char)data;
329
330 ret = write(fd, TxBuf, 2);
331 if (ret < 0)
332 printf("spi:SPI Write error\n");
333
334 usleep(10);
335
336 return ret;
337 }
338
339 unsigned char ReadRawRC(int addr) //向RC522 读数据
340 {
341 int ret;
342 int fd = g_SPI_Fd;
343 unsigned char ReData;
344 unsigned char Address;
345
346 Address = (unsigned char)addr << 1;
347 Address |= (1 << 7);
348 Address &= ~(1 << 0);
349
350 ret = write(fd, &Address, 1);
351 if (ret < 0)
352 printf("spi:SPI Write error\n");
353
354 usleep(100);
355
356 ret = read(fd, &ReData, 1);
357 if (ret < 0)
358 printf("spi:SPI Read error\n");
359
360 return ReData;
361 }
362
363 void SetBitMask(unsigned char reg,unsigned char mask)
364 {
365 char tmp = 0x0;
366
367 tmp = ReadRawRC(reg) | mask;
368
369 WriteRawRC(reg,tmp | mask);
370 }
371
372 //******************************************************************/
373 //功 能:清RC522寄存器位
374 //参数说明:reg[IN]:寄存器地址
375 // mask[IN]:清位值
376 //******************************************************************/
377 void ClearBitMask(unsigned char reg, unsigned char mask)
378 {
379 char tmp = 0x0;
380
381 tmp = ReadRawRC(reg)&(~mask);
382
383 WriteRawRC(reg, tmp); // clear bit mask
384 }
385
386 int rc522_init()
387 {
388 int ret;
389 char version = 0;
390
391 //reset
392 WriteRawRC(CommandReg, PCD_RESETPHASE);
393 usleep(10);
394 WriteRawRC(ModeReg, 0x3D);
395 WriteRawRC(TReloadRegL, 30);
396 WriteRawRC(TReloadRegH, 0);
397 WriteRawRC(TModeReg, 0x8D);
398 WriteRawRC(TPrescalerReg, 0x3E);
399
400 version = ReadRawRC(VersionReg);
401 printf("Chip Version: 0x%x\n", version);
402 usleep(50000);
403
404 return 0;
405 }
406
407 void PcdAntennaOn()
408 {
409 unsigned char i;
410
411 WriteRawRC(TxASKReg, 0x40);
412 usleep(20);
413
414 i = ReadRawRC(TxControlReg);
415 if(!(i&0x03))
416 SetBitMask(TxControlReg, 0x03);
417
418 i = ReadRawRC(TxASKReg);
419 }
420
421 static void print_usage(const char *prog)
422 {
423 printf("Usage: %s [-DsbdlHOLC3]\n", prog);
424 puts(" -D --device device to use (default /dev/spidev1.1)\n"
425 " -s --speed max speed (Hz)\n"
426 " -d --delay delay (usec)\n"
427 " -b --bpw bits per word \n"
428 " -l --loop loopback\n"
429 " -H --cpha clock phase\n"
430 " -O --cpol clock polarity\n"
431 " -L --lsb least significant bit first\n"
432 " -C --cs-high chip select active high\n"
433 " -3 --3wire SI/SO signals shared\n");
434 exit(1);
435 }
436
437 static void parse_opts(int argc, char *argv[])
438 {
439 while (1) {
440 static const struct option lopts[] = {
441 { "device", 1, 0, 'D' },
442 { "speed", 1, 0, 's' },
443 { "delay", 1, 0, 'd' },
444 { "bpw", 1, 0, 'b' },
445 { "loop", 0, 0, 'l' },
446 { "cpha", 0, 0, 'H' },
447 { "cpol", 0, 0, 'O' },
448 { "lsb", 0, 0, 'L' },
449 { "cs-high", 0, 0, 'C' },
450 { "3wire", 0, 0, '3' },
451 { "no-cs", 0, 0, 'N' },
452 { "ready", 0, 0, 'R' },
453 { NULL, 0, 0, 0 },
454 };
455 int c;
456
457 c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
458
459 if (c == -1)
460 break;
461
462 switch (c) {
463 case 'D':
464 device = optarg;
465 break;
466 case 's':
467 speed = atoi(optarg);
468 break;
469 case 'd':
470 delay = atoi(optarg);
471 break;
472 case 'b':
473 bits = atoi(optarg);
474 break;
475 case 'l':
476 mode |= SPI_LOOP;
477 break;
478 case 'H':
479 mode |= SPI_CPHA;
480 break;
481 case 'O':
482 mode |= SPI_CPOL;
483 break;
484 case 'L':
485 mode |= SPI_LSB_FIRST;
486 break;
487 case 'C':
488 mode |= SPI_CS_HIGH;
489 break;
490 case '3':
491 mode |= SPI_3WIRE;
492 break;
493 case 'N':
494 mode |= SPI_NO_CS;
495 break;
496 case 'R':
497 mode |= SPI_READY;
498 break;
499 default:
500 print_usage(argv[0]);
501 break;
502 }
503 }
504 }
505
506 //******************************************************************/
507 //功 能:通过RC522和ISO14443卡通讯
508 //参数说明:Command[IN]:RC522命令字
509 // pInData[IN]:通过RC522发送到卡片的数据
510 // InLenByte[IN]:发送数据的字节长度
511 // pOutData[OUT]:接收到的卡片返回数据
512 // *pOutLenBit[OUT]:返回数据的位长度
513 //******************************************************************/
514 char PcdComMF522(unsigned char Command, unsigned char *pInData,
515 unsigned char InLenByte, unsigned char *pOutData,
516 unsigned int *pOutLenBit)
517 {
518 char status = MI_ERR;
519 unsigned char irqEn = 0x00;
520 unsigned char waitFor = 0x00;
521 unsigned char lastBits;
522 unsigned char n;
523 unsigned int i;
524
525 switch (Command)
526 {
527 case PCD_AUTHENT:
528 irqEn = 0x12;
529 waitFor = 0x10;
530 break;
531 case PCD_TRANSCEIVE:
532 irqEn = 0x77;
533 waitFor = 0x30;
534 break;
535 default:
536 break;
537 }
538
539 WriteRawRC(ComIEnReg, irqEn|0x80);
540 ClearBitMask(ComIrqReg, 0x80);
541 WriteRawRC(CommandReg, PCD_IDLE);
542 SetBitMask(FIFOLevelReg, 0x80); // 清空FIFO
543 for(i=0; i<InLenByte; i++)
544 WriteRawRC(FIFODataReg, pInData[i]); // 数据写入FIFO
545
546 WriteRawRC(CommandReg, Command); // 命令写入命令寄存器
547
548 if(Command == PCD_TRANSCEIVE)
549 SetBitMask(BitFramingReg,0x80); // 开始发送
550
551 i = 6000; //根据时钟频率调整,操作M1卡最大等待时间25ms
552 do
553 {
554 n = ReadRawRC(ComIrqReg);
555 i--;
556 }
557 while((i!=0)&&!(n&0x01)&&!(n&waitFor));
558
559 ClearBitMask(BitFramingReg, 0x80);
560
561 if(i!=0)
562 {
563 if(!(ReadRawRC(ErrorReg) & 0x1B))
564 {
565 status = MI_OK;
566 if (n&irqEn&0x01)
567 status = MI_NOTAGERR;
568 if(Command == PCD_TRANSCEIVE)
569 {
570 n = ReadRawRC(FIFOLevelReg);
571
572 lastBits = ReadRawRC(ControlReg) & 0x07;
573 if(lastBits)
574 *pOutLenBit = (n-1)*8 + lastBits;
575 else
576 *pOutLenBit = n*8;
577
578 if(n == 0)
579 n = 1;
580 if(n>MAXRLEN)
581 n = MAXRLEN;
582
583 for (i=0; i<n; i++)
584 pOutData[i] = ReadRawRC(FIFODataReg);
585 }
586 }
587 else
588 {
589 status = MI_ERR;
590 }
591 }
592
593 SetBitMask(ControlReg, 0x80);// stop timer now
594 WriteRawRC(CommandReg, PCD_IDLE);
595
596 return status;
597 }
598
599 char PcdRequest(unsigned char req_code, unsigned char *pTagType)
600 {
601 char status;
602 unsigned int unLen;
603 unsigned char ucComMF522Buf[MAXRLEN];
604
605 ClearBitMask(Status2Reg, 0x08);
606 WriteRawRC(BitFramingReg, 0x07);
607 SetBitMask(TxControlReg, 0x03);
608
609 ucComMF522Buf[0] = req_code;
610
611 status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf,
612 1, ucComMF522Buf, &unLen);
613
614 if ((status == MI_OK) && (unLen == 0x10))
615 {
616 *pTagType = ucComMF522Buf[0];
617 *(pTagType+1) = ucComMF522Buf[1];
618 }
619 else
620 {
621 status = MI_ERR;
622 }
623
624 return status;
625 }
626
627 //******************************************************************/
628 //功 能:防冲撞 /
629 //参数说明: pSnr[OUT]:卡片序列号,4字节 /
630 //返 回: 成功返回MI_OK /
631 //******************************************************************/
632 char PcdAnticoll(unsigned char *pSnr)
633 {
634 char status;
635 unsigned char i, snr_check = 0;
636 unsigned int unLen;
637 unsigned char ucComMF522Buf[MAXRLEN];
638
639 ClearBitMask(Status2Reg, 0x08);
640 WriteRawRC(BitFramingReg, 0x00);
641 ClearBitMask(CollReg, 0x80);
642
643 ucComMF522Buf[0] = PICC_ANTICOLL1;
644 ucComMF522Buf[1] = 0x20;
645
646 status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf,
647 2, ucComMF522Buf, &unLen);
648
649 if(status == MI_OK)
650 {
651 for (i=0; i<4; i++)
652 {
653 *(pSnr+i) = ucComMF522Buf[i];
654 snr_check ^= ucComMF522Buf[i];
655 }
656 if (snr_check != ucComMF522Buf[i])
657 {
658 status = MI_ERR;
659 }
660 }
661
662 SetBitMask(CollReg,0x80);
663
664 return status;
665 }
666
667 void Find_Card(void)
668 {
669 if(PcdRequest(0x52, Temp) == MI_OK)
670 {
671 if(Temp[0]==0x04 && Temp[1]==0x00)
672 printf("MFOne-S50\n");
673 else if(Temp[0]==0x02 && Temp[1] == 0x00)
674 printf("MFOne-S70\n");
675 else if(Temp[0]==0x44 && Temp[1]==0x00)
676 printf("MF-UltraLight\n");
677 else if(Temp[0]==0x08 && Temp[1]==0x00)
678 printf("MF-Pro\n");
679 else if(Temp[0]==0x44 && Temp[1]==0x03)
680 printf("MF Desire\n");
681 else
682 printf("Unknown\n");
683
684 printf("SUCCESS!\n");
685 }
686 else
687 {
688 printf("No card!\n");
689 }
690 }
691
692 void Auto_Reader(void)
693 {
694 int i = 0;
695 unsigned long num = 0;
696
697 // while(1)
698 //{
699 if(PcdRequest(0x52,Temp) == MI_OK)
700 {
701 if(Temp[0]==0x04 && Temp[1]==0x00)
702 printf("MFOne-S50\n");
703 else if(Temp[0]==0x02 && Temp[1]==0x00)
704 printf("MFOne-S70\n");
705 else if(Temp[0]==0x44 && Temp[1]==0x00)
706 printf("MF-UltraLight\n");
707 else if(Temp[0]==0x08 && Temp[1]==0x00)
708 printf("MF-Pro\n");
709 else if(Temp[0]==0x44 && Temp[1]==0x03)
710 printf("MF Desire\n");
711 else
712 printf("Unknown\n");
713
714 if(PcdAnticoll(UID) == MI_OK)
715 {
716 printf("Card Id is(%d):", num++);
717 #if 1
718 for(i=0; i<4; i++)
719 printf("%x", UID[i]);
720 #else
721 tochar(UID[0]);
722 tochar(UID[1]);
723 tochar(UID[2]);
724 tochar(UID[3]);
725 #endif
726 printf("\n");
727
728 PcdRequest(0x52,Temp);//clear
729 }
730 else
731 {
732 printf("no serial num read\n");
733 }
734 }
735 else
736 {
737 printf("No Card!\n");
738 }
739
740 usleep(300000);
741 // }
742 }
743
744 void HandleConfigMenu(unsigned char inputvalue)
745 {
746 #if 0
747 switch(toupper(inputvalue))
748 {
749 case 'A':
750 Auto_Reader();
751 break;
752 case 'F':
753 Find_Card();
754 break;
755 default:
756 DisplayConfigMenu();
757 }
758 #endif
759
760 //Find_Card();
761
762 Auto_Reader();
763 }
764
765 int main(int argc, char *argv[])
766 {
767 unsigned char i;
768
769 int ret = 0;
770 int fd;
771
772 parse_opts(argc, argv);
773
774 fd = open(device, O_RDWR);
775 if (fd < 0)
776 pabort("can't open device");
777
778 g_SPI_Fd = fd;
779
780 #if 0
781 /*
782 * spi mode
783 */
784 ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
785 if (ret == -1)
786 pabort("can't set spi mode");
787
788 ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
789 if (ret == -1)
790 pabort("can't get spi mode");
791
792 /*
793 * bits per word
794 */
795 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
796 if (ret == -1)
797 pabort("can't set bits per word");
798
799 ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
800 if (ret == -1)
801 pabort("can't get bits per word");
802
803 /*
804 * max speed hz
805 */
806 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
807 if (ret == -1)
808 pabort("can't set max speed hz");
809
810 ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
811 if (ret == -1)
812 pabort("can't get max speed hz");
813
814 printf("spi mode: %d\n", mode);
815 printf("bits per word: %d\n", bits);
816 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
817 #endif
818
819 rc522_init();
820
821 PcdAntennaOn();
822
823 HandleConfigMenu(i);
824
825 close(fd);
826
827 return ret;
828 }
spi_test_app