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 }