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_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");

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 }