1 Star 0 Fork 10

PaulJiang/Linux RC522 SPI S50 Read Card Device Drivers

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
gt2440_rc522.c 47.00 KB
一键复制 编辑 原始数据 按行查看 历史
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571
/*
* /linux-3.0.8/drivers/spi/gt2440_rc522.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <asm/uaccess.h>
#include "gt2440_rc522.h"
#include "rc522_test.h"
/***** data structure****/
static DECLARE_BITMAP(minors, N_SPI_MINORS);
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
static unsigned bufsize = 4096;
static struct class *gt2440_rc522_class = NULL;
static struct spi_master *master = NULL;
static struct spi_device * spi = NULL;
static const struct file_operations gt2440_rc522_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = gt2440_rc522_ioctl,
.compat_ioctl = gt2440_rc522_ioctl,
.open = gt2440_rc522_open,
.release = gt2440_rc522_release,
};
/***** write, read reg help function *****/
static int gt2440_rc522_write_reg (struct gt2440_rc522_info *info,
unsigned char reg, unsigned char value)
{
int ret;
unsigned char tx_buf[4];
tx_buf[0] = (reg << 1) & 0x7e;
tx_buf[1] = value;
ret = spi_write(info->spi_dev, tx_buf, 2);
if (ret)
dprintk("failed to write reg: "
"addr=0x%02x, value=0x%02x, ret = %d\n",
reg,value,ret);
return ret;
}
static int gt2440_rc522_read_reg (struct gt2440_rc522_info *info,
unsigned char reg,unsigned char *value)
{
unsigned char tx_buf[4];
unsigned char rx_buf[4];
int ret;
tx_buf[0] = (reg << 1) & 0x7e | 0x80;
ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, 1);
if (ret)
dprintk("failed to read reg: "
"addr=0x%02x, value=0x%02x, ret = %d\n",
reg,*value,ret);
else
*value = rx_buf[0];
return ret;
}
static int gt2440_rc522_write_buf(struct gt2440_rc522_info *info,
unsigned char reg, unsigned char *buf, unsigned char len)
{
int ret;
unsigned char tx_buf[INFO_BUFFER_SIZE + 1];
tx_buf[0] = (reg << 1) & 0x7e;
memcpy(&tx_buf[1], buf, len);
ret = spi_write(info->spi_dev, tx_buf, len+1);
if (ret)
dprintk("failed to write buf: "
"addr=0x%02x, value=0x%02x, ret = %d\n",
reg,*buf,ret);
return ret;
}
/****** the fuction has bug, do not use *****/
static int gt2440_rc522_read_buf(struct gt2440_rc522_info *info,
unsigned char reg, unsigned char *buf, unsigned char len)
{
struct spi_message message;
u8 tx_buf[32] = {0};
int ret;
tx_buf[0] = (reg << 1) & 0x7e | 0x80;
struct spi_transfer xfer = {
.tx_buf = tx_buf,
.rx_buf = buf,
.len = len,
};
memset(&tx_buf[1], tx_buf[0], len-1);
spi_message_init(&message);
spi_message_add_tail(&xfer, &message);
ret = spi_async(info->spi_dev, &message);
if (ret)
dprintk("failed to read buf: "
"addr=0x%02x, value=0x%02x, ret = %d\n",
reg,*buf,ret);
return ret;
}
static int gt2440_rc522_set_bitmask (struct gt2440_rc522_info *info,
unsigned char reg, unsigned char mask)
{
unsigned char tmp = 0x00;
int ret = 0;
gt2440_rc522_read_reg(info, reg, &tmp);
gt2440_rc522_write_reg(info, reg, tmp | mask);
return ret;
}
static int gt2440_rc522_clear_bitmask (struct gt2440_rc522_info *info,
unsigned char reg, unsigned char mask)
{
unsigned char tmp = 0x00;
int ret = 0;
gt2440_rc522_read_reg(info, reg, &tmp);
gt2440_rc522_write_reg(info, reg, tmp & ~mask);
return ret;
}
/***** rc522 help function *****/
static int gt2440_rc522_reset_chip(struct gt2440_rc522_info *info)
{
int ret = 0;
if(ret = gt2440_rc522_write_reg(info, COMMAND_REG, PCD_RESETPHASE)) return ret;
msleep(50);
gt2440_rc522_write_reg(info, MODE_REG, 0x3D);
gt2440_rc522_write_reg(info, T_RELOAD_REG_L, 30);
gt2440_rc522_write_reg(info, T_RELOAD_REG_H, 0);
gt2440_rc522_write_reg(info, T_MODE_REG, 0x8D);
gt2440_rc522_write_reg(info, T_PRESCALER_REG, 0x3E);
gt2440_rc522_write_reg(info, TX_AUTO_REG, 0x40);
return ret;
}
static int gt2440_rc522_enable_antenna(struct gt2440_rc522_info *info)
{
unsigned char reg_val = 0;
int ret = 0;
if(!(reg_val & 0x03))
gt2440_rc522_set_bitmask(info,TX_CONTROL_REG,0x03);
return ret;
}
static int gt2440_rc522_disable_antenna(struct gt2440_rc522_info *info)
{
int ret = 0;
gt2440_rc522_clear_bitmask(info,TX_CONTROL_REG,0x03);
return ret;
}
static int gt2440_rc522_config_isotype(struct gt2440_rc522_info *info,
unsigned char type)
{
int ret = 0;
if(type == 'A'){
gt2440_rc522_clear_bitmask(info,STATUS2_REG, 0x08);
gt2440_rc522_write_reg(info, MODE_REG, 0x3D);
gt2440_rc522_write_reg(info, RX_SEL_REG, 0x86);
gt2440_rc522_write_reg(info, RF_CFG_REG, 0x7f);
gt2440_rc522_write_reg(info, T_RELOAD_REG_L, 30);
gt2440_rc522_write_reg(info, T_RELOAD_REG_H, 0);
gt2440_rc522_write_reg(info, T_MODE_REG, 0x8D);
gt2440_rc522_write_reg(info, T_PRESCALER_REG, 0x3E);
gt2440_rc522_enable_antenna(info);
}else{
dprintk("failed to surpport iso type");
return MI_ERR;
}
return ret;
}
static int gt2440_rc522_init_chip(struct gt2440_rc522_info *info)
{
int ret = 0;
if(ret = gt2440_rc522_reset_chip(info)) return ret;
gt2440_rc522_disable_antenna(info);
msleep(50);
gt2440_rc522_enable_antenna(info);
gt2440_rc522_config_isotype(info, 'A');
return ret;
}
/***** rc522 card ops function *****/
static int gt2440_rc522_com_card(struct gt2440_rc522_info *info,
unsigned char cmd, unsigned char *tx_buf,
unsigned char tx_len, unsigned char *rx_buf,
unsigned int *rx_len_bit)
{
unsigned char irq_en = 0x00;
unsigned char wait_for = 0x00;
unsigned char last_bits = 0x00;
unsigned char reg_val = 0x00;
unsigned char com_irq_reg = 0x00;
unsigned int i;
unsigned long long cur_usec,last_usec;
int status = MI_ERR ;
switch(cmd){
case PCD_AUTHENT:
irq_en = 0x12;
wait_for = 0x10;
break;
case PCD_TRANSCEIVE:
irq_en = 0x77;
wait_for = 0x30;
break;
default:
break;
}
gt2440_rc522_write_reg(info, COM_IEN_REG, irq_en | 0x80);
gt2440_rc522_clear_bitmask(info, COM_IRQ_REG, 0x80);
gt2440_rc522_write_reg(info, COMMAND_REG, PCD_IDLE);
gt2440_rc522_set_bitmask(info, FIFO_LEVEL_REG, 0x80);
// critical code: carefull !!!
gt2440_rc522_write_buf(info, FIFO_DATA_REG, tx_buf, tx_len);
gt2440_rc522_write_reg(info, COMMAND_REG, cmd);
if(cmd == PCD_TRANSCEIVE)
gt2440_rc522_set_bitmask(info, BIT_FRAMING_REG, 0x80);
i =10;
do{
if(status = gt2440_rc522_read_reg(info, COM_IRQ_REG, &com_irq_reg))
return status;
msleep(50); // must delay > 25 ms,
i--;
}while((i != 0) &&
!(com_irq_reg & 0x01) &&
!(com_irq_reg & wait_for));
/*
dprintk("i= %d, read com_irq_reg: 0x%02x, 0x%02x\n",
i,COM_IRQ_REG, com_irq_reg);
*/
gt2440_rc522_clear_bitmask(info, BIT_FRAMING_REG, 0x80);
if(i != 0){
gt2440_rc522_read_reg(info, ERROR_REG, &reg_val);
/*
dprintk("read error reg: 0x%02x, 0x%02x,\n",
ERROR_REG,reg_val);
*/
if(!(reg_val & 0x1B)){ /* reg_val = 0x00 */
status = MI_OK ;
/* com_irq_reg = 0x64, irq_en = 0x77 */
if(com_irq_reg & irq_en & 0x01)
status = MI_NOTAGERR;
if(cmd == PCD_TRANSCEIVE){
gt2440_rc522_read_reg(info, FIFO_LEVEL_REG, &reg_val);
gt2440_rc522_read_reg(info, CONTROL_REG, &last_bits);
/*
dprintk("read fifo level reg: 0x%02x, 0x%02x,\n",
FIFO_LEVEL_REG,reg_val);
dprintk("read control reg: 0x%02x, 0x%02x,\n",
CONTROL_REG,last_bits);
*/
last_bits = last_bits & 0x07;
if(last_bits)
*rx_len_bit = (reg_val - 1) * 8 + last_bits;
else
*rx_len_bit = reg_val * 8;
if(0 == reg_val)
reg_val = 1;
if(reg_val > DEF_FIFO_LENGTH)
reg_val = 64;
/* gt2440_rc522_read_buf(info, FIFO_DATA_REG, rx_buf, reg_val); */
for(i = 0; i<reg_val; i++)
gt2440_rc522_read_reg(info, FIFO_DATA_REG, &rx_buf[i]);
/*
dprintk("read FIFO data:");
for(i = 0; i<reg_val; i++){
if(i%4 == 0) dprintk("\n");
dprintk("0x%02x ",rx_buf[i]);
}
dprintk("\nread FIFO data: end\n");
*/
}
}else{
dprintk("failed to read irq reg: addr=0x%02x, value=0x%02x\n" ,
COM_IRQ_REG, com_irq_reg);
status = MI_ERR;
}
}
gt2440_rc522_set_bitmask(info, CONTROL_REG, 0x80);
gt2440_rc522_write_reg(info, COMMAND_REG, PCD_IDLE);
return status;
}
static int gt2440_rc522_calulatate_crc(struct gt2440_rc522_info *info,
unsigned char *tx_buf, unsigned char tx_len, unsigned char *rx_buf)
{
unsigned char reg_val = 0;
int status = 0;
gt2440_rc522_clear_bitmask(info, DIV_IRQ_REG, 0x04);
gt2440_rc522_write_reg(info, COMMAND_REG, PCD_IDLE);
gt2440_rc522_set_bitmask(info, FIFO_LEVEL_REG, 0x80);
gt2440_rc522_write_buf(info, FIFO_DATA_REG, tx_buf, tx_len);
gt2440_rc522_write_reg(info, COMMAND_REG, PCD_CALCCRC);
int i = 10;
do{ if(status = gt2440_rc522_read_reg(info, DIV_IRQ_REG, &reg_val))
return status;
msleep(50);// must delay > 25 ms,
}while ((i != 0) && !(reg_val & 0x04));
gt2440_rc522_read_reg(info, CRC_RESULT_REG_L, &rx_buf[0]);
gt2440_rc522_read_reg(info, CRC_RESULT_REG_M, &rx_buf[1]);
return status;
}
/***** rc522 ops function *****/
static int gt2440_rc522_halt_chip(struct gt2440_rc522_info *info)
{
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned int rx_len_bit;
int status;
int ret = 0;
tx_buf[0] = PICC_HALT;
tx_buf[1] = 0;
if(ret = gt2440_rc522_calulatate_crc(info, tx_buf, 2, &tx_buf[2]))
return ret;
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 2 + CARD_CRC_SIZE, rx_buf, &rx_len_bit);
return status;
}
static int gt2440_rc522_request_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned int rx_len_bit;
int status = 0, i = 0;
tx_buf[0] = PICC_REQIDL;
gt2440_rc522_clear_bitmask(info, STATUS2_REG, 0x08);
gt2440_rc522_write_reg(info, BIT_FRAMING_REG, 0x07);
gt2440_rc522_set_bitmask(info, TX_CONTROL_REG, 0x03);
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 1, rx_buf, &rx_len_bit);
if((status == MI_OK) && (rx_len_bit == 0x10)){
memcpy(&xfer->txrx_buf[0], rx_buf, CARD_TYPE_SIZE);
/*card type : 0x04,0x00, S50 card */
}else{
dprintk("failed to request card : %d\n" , status);
for(i=0; i < rx_len_bit/8; i ++){
dprintk("0x%02x, " , rx_buf[i]);
}
dprintk("\nfailed to request card : end\n");
}
return status;
}
static int gt2440_rc522_anticoll_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned char id_csum = 0;
unsigned int rx_len_bit;
int status = 0, i = 0;
tx_buf[0] = PICC_ANTICOLL1;
tx_buf[1] = 0x20;
gt2440_rc522_clear_bitmask(info, STATUS2_REG, 0x08);
gt2440_rc522_write_reg(info, BIT_FRAMING_REG, 0x00);
gt2440_rc522_clear_bitmask(info, COLL_REG, 0x80);
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 2, rx_buf, &rx_len_bit);
/*dprintk("len bit: 0x%02x \n", rx_len_bit);*/
if(status == MI_OK){
for(i = 0; i < CARD_ID_SIZE; i++) id_csum ^= rx_buf[i];
if(id_csum != rx_buf[i]) {
dprintk("failed to check sum card id: %d\n" , status);
for(i=0; i < rx_len_bit/8; i ++){
dprintk("0x%02x, " , rx_buf[i]);
}
dprintk("\nfailed to check sum card id: end\n");
status = MI_ERR;
}// check sum: 0x5b
memcpy(&xfer->txrx_buf[CARD_TYPE_SIZE],
rx_buf, CARD_ID_SIZE + CARD_IDCSUM_SIZE);
}
gt2440_rc522_set_bitmask(info, COLL_REG, 0x80);
return status;
}
static int gt2440_rc522_select_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned int rx_len_bit;
int status = 0, i = 0;
tx_buf[0] = PICC_ANTICOLL1;
tx_buf[1] = 0x70;
tx_buf[6] = 0;
for(i = 0; i < CARD_ID_SIZE; i++){
tx_buf[2 + i] = xfer->txrx_buf[CARD_TYPE_SIZE + i];
tx_buf[6] ^= xfer->txrx_buf[CARD_TYPE_SIZE + i] ;
}
if(status = gt2440_rc522_calulatate_crc(info, tx_buf,
2 + CARD_ID_SIZE + CARD_IDCSUM_SIZE ,
&tx_buf[2 + CARD_ID_SIZE + CARD_IDCSUM_SIZE]))
return status;
gt2440_rc522_clear_bitmask(info, STATUS2_REG, 0x08);
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 2 + CARD_ID_SIZE + CARD_IDCSUM_SIZE + CARD_CRC_SIZE,
rx_buf, &rx_len_bit);
if((status == MI_OK) && (rx_len_bit == (unsigned int)0x18)){
memcpy(&xfer->txrx_buf[CARD_TYPE_SIZE + CARD_ID_SIZE + CARD_IDCSUM_SIZE],
rx_buf, CARD_CAP_SIZE + CARD_MSG_SIZE);// card capacity: 8K bits
}else{
dprintk("failed to select card: %d\n" , status);
for(i=0; i < rx_len_bit/8; i ++){
dprintk("0x%02x, " , rx_buf[i]);
}
dprintk("\nfailed to select card: end\n");
status = MI_ERR;
}
return status;
}
static int gt2440_rc522_auth_key(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned char *key_buf;
unsigned char reg_val = 0;
unsigned int rx_len_bit;
int status = 0, i = 0;
switch(xfer->key_type){
case RC522_KEY_A:
tx_buf[0] = PICC_AUTHENT1A;
key_buf = xfer->keya_buf;
break;
case RC522_KEY_B:
tx_buf[0] = PICC_AUTHENT1B;
key_buf = xfer->keyb_buf;
break;
default:
tx_buf[0] = PICC_AUTHENT1A;
key_buf = xfer->keya_buf;
break;
}
tx_buf[1] = (xfer->sect_num * CARD_SECT_NBLK ) + xfer->blk_num;
memcpy(tx_buf + 2, key_buf, CARD_KEYA_SIZE);
memcpy(tx_buf+2 + CARD_KEYA_SIZE, xfer->id_buf, CARD_ID_SIZE);
status = gt2440_rc522_com_card(info, PCD_AUTHENT,
tx_buf, 2 + CARD_KEYA_SIZE + CARD_ID_SIZE,
rx_buf, &rx_len_bit);
gt2440_rc522_read_reg(info, STATUS2_REG, &reg_val);
if((status != MI_OK) || (!(reg_val & 0x08))){
dprintk("failed to auth card: key type=0x%02x,status=%d\n" ,
tx_buf[0], status);
//for(i=0; i < rx_len_bit/8; i ++){
// dprintk("0x%02x, " , rx_buf[i]);
//}
dprintk("\nfailed to auth card: end\n");
status = MI_ERR;
}
return status;
}
static int gt2440_rc522_auth_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{ //dprintk("gt2440_rc522_auth_card()\n");
int status = 0;
switch(xfer->key_type){
case RC522_KEY_A:
case RC522_KEY_B:
status = gt2440_rc522_auth_key(info, xfer);
break;
case RC522_KEY_A_B:
xfer->key_type = RC522_KEY_A;
status = gt2440_rc522_auth_key(info, xfer);
xfer->key_type = RC522_KEY_B;
status = gt2440_rc522_auth_key(info, xfer);
break;
default:
xfer->key_type = RC522_KEY_A;
status = gt2440_rc522_auth_key(info, xfer);
break;
}
return status;
}
static int gt2440_rc522_read_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{ //dprintk("gt2440_rc522_read_card(): start\n");
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned int rx_len_bit;
int status = 0, i = 0;
tx_buf[0] = PICC_READ;
tx_buf[1] = (xfer->sect_num * CARD_SECT_NBLK ) + xfer->blk_num;
if(status = gt2440_rc522_calulatate_crc(info, tx_buf, 2, &tx_buf[2]))
return status;
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 2 + CARD_CRC_SIZE, rx_buf, &rx_len_bit);
if((status == MI_OK) && (rx_len_bit == 0x90)){
memcpy(xfer->txrx_buf, rx_buf, CARD_BLK_SIZE + CARD_PLUS_SIZE);
}else{
dprintk("failed to read card: %d\n" , status);
for(i=0; i < rx_len_bit/8; i ++){
dprintk("0x%02x, " , rx_buf[i]);
}
dprintk("\nfailed to read card: end\n");
status = MI_ERR;
}
//dprintk("gt2440_rc522_read_card(): end\n");
return status;
}
static int gt2440_rc522_write_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{ //dprintk("gt2440_rc522_write_card()\n");
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned int rx_len_bit;
int status = 0, i =0;
tx_buf[0] = PICC_WRITE;
tx_buf[1] = (xfer->sect_num * CARD_SECT_NBLK ) + xfer->blk_num;
if(status = gt2440_rc522_calulatate_crc(info, tx_buf, 2, &tx_buf[2]))
return status;
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 2 + CARD_CRC_SIZE,
rx_buf, &rx_len_bit);
if((status == MI_OK) && (rx_len_bit == 4) && ((rx_buf[0] & 0x0F) == 0x0A)){
memcpy(tx_buf, xfer->txrx_buf, CARD_BLK_SIZE);
if(status = gt2440_rc522_calulatate_crc(info, tx_buf,
CARD_BLK_SIZE, &tx_buf[CARD_BLK_SIZE]))
return status;
status = gt2440_rc522_com_card(info,PCD_TRANSCEIVE,
tx_buf, CARD_BLK_SIZE + CARD_CRC_SIZE,
tx_buf, &rx_len_bit);
if((status != MI_OK)){
dprintk("failed to write card: %d\n" , status);
for(i=0; i < rx_len_bit/8; i ++){
dprintk("0x%02x, " , rx_buf[i]);
}
dprintk("\nfailed to write card: end\n");
status = MI_ERR;
}
}
return status;
}
static int gt2440_rc522_inc_dec_card(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{ //dprintk("gt2440_rc522_inc_dec_card(): start\n");
unsigned char *tx_buf = info->tx_buffer;
unsigned char *rx_buf = info->rx_buffer;
unsigned int rx_len_bit;
int status = 0, i = 0;
switch(xfer->ioc_type){
case RC522_IOC_INC_CARD:
tx_buf[0] = PICC_INCREMENT;
break;
case RC522_IOC_DEC_CARD:
tx_buf[0] = PICC_DECREMENT;
break;
default:
dprintk("\nfailed to surpport ioc type\n");
status = MI_ERR;
return status;
}
tx_buf[1] = (xfer->sect_num * CARD_SECT_NBLK ) + xfer->blk_num;
if(status = gt2440_rc522_calulatate_crc(info, tx_buf, 2, &tx_buf[2]))
return status;
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, 2 + CARD_CRC_SIZE,
rx_buf, &rx_len_bit);
if ((status == MI_OK) && (rx_len_bit == 4) && ((rx_buf[0] & 0x0F) == 0x0A)){
memcpy(tx_buf, xfer->txrx_buf, CARD_INC_SIZE);
if(status = gt2440_rc522_calulatate_crc(info, tx_buf,
CARD_INC_SIZE, &tx_buf[CARD_INC_SIZE]))
return status;
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf, CARD_INC_SIZE + CARD_CRC_SIZE,
rx_buf, &rx_len_bit);
if(status == MI_OK){
tx_buf[0] = PICC_TRANSFER;
tx_buf[1] = (xfer->sect_num * CARD_SECT_NBLK ) + xfer->blk_num;
if(status = gt2440_rc522_calulatate_crc(info, tx_buf, 2, &tx_buf[2]))
return status;
status = gt2440_rc522_com_card(info, PCD_TRANSCEIVE,
tx_buf,2 + CARD_CRC_SIZE,
rx_buf,&rx_len_bit);
if ((status == MI_OK) &&
(rx_len_bit == 4) &&
((rx_buf[0] & 0x0F) == 0x0A)){
status = MI_OK;
}else{
dprintk("failed to inc_dec card: %d\n" , status);
for(i=0; i < rx_len_bit/8; i ++){
dprintk("0x%02x, " , rx_buf[i]);
}
dprintk("\nfailed to inc_dec card: end\n");
status = MI_ERR;
}
}
}
//dprintk("gt2440_rc522_inc_dec_card(): end\n");
return status;
}
static int gt2440_rc522_read_keya(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int status = 0;
unsigned char buf[CARD_KEYA_SIZE] = {0x00};
status = gt2440_rc522_read_card(info, xfer);
if(status == MI_OK){
/***** must clean txrx_buf(avoid user to get msg) , then copy old_buf to it . *****/
memcpy(buf, &xfer->txrx_buf[0], CARD_KEYA_SIZE);
memset(xfer->txrx_buf, 0x00, CARD_BLK_SIZE + CARD_PLUS_SIZE);
memcpy(xfer->txrx_buf, buf, CARD_KEYA_SIZE);
}
return status;
}
static int gt2440_rc522_read_keyb(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int status = 0;
unsigned char buf[CARD_KEYB_SIZE] = {0x00};
status = gt2440_rc522_read_card(info, xfer);
if(status == MI_OK){
/***** must clean txrx_buf(avoid user to get msg) , then copy old_buf to it . *****/
memcpy(buf, &xfer->txrx_buf[CARD_KEYA_SIZE + CARD_CTRL_SIZE],
CARD_KEYB_SIZE);
memset(xfer->txrx_buf, 0x00, CARD_BLK_SIZE + CARD_PLUS_SIZE);
memcpy(xfer->txrx_buf, buf, CARD_KEYB_SIZE);
}
return status;
}
static int gt2440_rc522_read_ctrl(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int status = 0;
unsigned char buf[CARD_CTRL_SIZE] = {0};
status = gt2440_rc522_read_card(info, xfer);
if(status == MI_OK){
/***** must clean txrx_buf(avoid user to get msg) , then copy old_buf to it . *****/
memcpy(buf, &xfer->txrx_buf[CARD_KEYA_SIZE], CARD_CTRL_SIZE);
memset(xfer->txrx_buf, 0x00, CARD_BLK_SIZE + CARD_PLUS_SIZE);
memcpy(xfer->txrx_buf, buf, CARD_CTRL_SIZE);
}else{
}
return status;
}
static int gt2440_rc522_write_keya(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int status = 0;
unsigned char buf[CARD_KEYA_SIZE] = {0};
unsigned char old_buf[CARD_KEYA_SIZE] = {0};
memcpy(buf, &xfer->txrx_buf[0], CARD_KEYA_SIZE); /* save writed key */
status = gt2440_rc522_read_card(info, xfer);
if(status == MI_OK){
/***** must clean txrx_buf(avoid user to get msg) , then copy old_buf to it . *****/
memcpy(old_buf, &xfer->txrx_buf[0], CARD_KEYA_SIZE); /* save old key to return user */
memcpy(&xfer->txrx_buf[0], buf, CARD_KEYA_SIZE); /* copy writed key to kay space*/
status = gt2440_rc522_write_card(info, xfer);
memset(xfer->txrx_buf, 0x00, CARD_BLK_SIZE + CARD_PLUS_SIZE);
if(status == MI_OK){
memcpy(&xfer->txrx_buf[0], old_buf, CARD_KEYA_SIZE); /* return old key */
}
}
return status;
}
static int gt2440_rc522_write_keyb(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int status = 0;
unsigned char buf[CARD_KEYB_SIZE] = {0};
unsigned char old_buf[CARD_KEYB_SIZE] = {0};
memcpy(buf, &xfer->txrx_buf[0], CARD_KEYB_SIZE); /* save writed key */
status = gt2440_rc522_read_card(info, xfer);
if(status == MI_OK){
memcpy(old_buf,&xfer->txrx_buf[CARD_KEYA_SIZE + CARD_CTRL_SIZE],
CARD_KEYB_SIZE); /* save old key to return user */
/***** critical code: because do not read keya from card,
****** so must write the keya_buf to keya space .
****** must clean txrx_buf(avoid user to get msg) , then copy old_buf to it .
*****/
memcpy(&xfer->txrx_buf[0], xfer->keya_buf, CARD_KEYA_SIZE);
memcpy(&xfer->txrx_buf[CARD_KEYA_SIZE + CARD_CTRL_SIZE],
buf,CARD_KEYB_SIZE); /* copy writed key to kay space*/
status = gt2440_rc522_write_card(info, xfer);
memset(xfer->txrx_buf, 0x00,
CARD_BLK_SIZE + CARD_PLUS_SIZE);
if(status == MI_OK){
memcpy(&xfer->txrx_buf[0], old_buf,CARD_KEYB_SIZE); /* return old key */
}
}
return status;
}
static int gt2440_rc522_write_ctrl(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int status = 0;
unsigned char buf[CARD_CTRL_SIZE] = {0};
unsigned char old_buf[CARD_CTRL_SIZE] = {0};
memcpy(buf, &xfer->txrx_buf[0], CARD_CTRL_SIZE); /* save writed ctrl area */
status = gt2440_rc522_read_card(info, xfer);
if(status == MI_OK){
memcpy(old_buf,&xfer->txrx_buf[CARD_KEYA_SIZE],
CARD_CTRL_SIZE); /* save old ctrl area to return user */
/***** critical code: because do not read keya from card,
****** so must write the keya_buf to keya space .
****** must clean txrx_buf(avoid user to get msg) ,
****** then copy old_buf to it .
*****/
memcpy(&xfer->txrx_buf[0], xfer->keya_buf, CARD_KEYA_SIZE);
memcpy(&xfer->txrx_buf[CARD_KEYA_SIZE], buf,CARD_CTRL_SIZE); /* copy writed ctrl to ctrl space*/
memcpy(&xfer->txrx_buf[CARD_KEYA_SIZE + CARD_CTRL_SIZE],
xfer->keyb_buf, CARD_KEYB_SIZE);
status = gt2440_rc522_write_card(info, xfer);
memset(xfer->txrx_buf, 0x00, CARD_BLK_SIZE + CARD_PLUS_SIZE);
if(status == MI_OK){
memcpy(&xfer->txrx_buf[0], old_buf,CARD_CTRL_SIZE); /* return old ctrl area */
}
}
return status;
}
static int gt2440_rc522_pass_op(struct gt2440_rc522_info *info,
struct rc522_ioc_transfer *xfer)
{
int ret = 0;
int i = 0;
switch(xfer->ioc_type){
case RC522_IOC_NONE_0:
break;
case RC522_IOC_INIT_CHIP:
if(info->users >= 2){
dprintk("failed to init chip: \n");
ret = -EBUSY;
break;
}
ret = gt2440_rc522_init_chip(info);
if(ret){
dprintk("failed to init chip: \n");
ret = -ENODEV;
}
break;
case RC522_IOC_HALT_CHIP:
if(info->users >= 2){
dprintk("failed to init chip: \n");
ret = -EBUSY;
break;
}
ret = gt2440_rc522_halt_chip(info);
if(ret){
dprintk("failed to halt chip: \n");
ret = -ENODEV;
}
break;
case RC522_IOC_ON_ANTE:
//ret = gt2440_rc522_enable_antenna(info);
break;
case RC522_IOC_OFF_ANTE:
//gt2440_rc522_disable_antenna(info);
break;
case RC522_IOC_ON_CHIP:
//ret = gt2440_rc522_enable_chip(info);
break;
case RC522_IOC_OFF_CHIP:
//gt2440_rc522_disable_chip(info);
break;
case RC522_IOC_REQ_CARD:
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_request_card(info,xfer); /* get card type*/
if(ret){
dprintk("failed to request card\n");
ret = -ENODEV;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_anticoll_card(info, xfer); /* get card id, id csum*/
if(ret){
dprintk("failed to anticoll card\n");
ret = -EACCES;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_select_card(info, xfer); /* get card capacity, card plus msg */
if(ret){
dprintk("failed to select card\n");
ret = -EACCES;
break;
}
memcpy(xfer->id_buf, &xfer->txrx_buf[CARD_TYPE_SIZE], CARD_ID_SIZE);
break;
case RC522_IOC_READ_CARD:
if(xfer->sect_num < RC522_SECT_0 ||
xfer->blk_num < RC522_BLK_0 ||
xfer->blk_num >= RC522_BLK_3){
dprintk("failed to read ctrl blk(3) data directly\n");
ret = -EINVAL;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_read_card(info,xfer);
if(ret){dprintk("failed to read card\n");
ret = -EINVAL;
break;
}
break;
case RC522_IOC_WRITE_CARD:
if(xfer->sect_num < RC522_SECT_0 ||
xfer->blk_num < RC522_BLK_0 ||
xfer->blk_num >= RC522_BLK_3){
dprintk("failed to write ctrl blk(3) data directly\n");
ret = -EINVAL;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_write_card(info,xfer);
if(ret){
dprintk("failed to write card\n");
ret = -EINVAL;
break;
}
break;
/***** inc and dec card *****/
case RC522_IOC_INC_CARD:
case RC522_IOC_DEC_CARD:
if(xfer->sect_num < RC522_SECT_0 ||
xfer->blk_num < RC522_BLK_0 ||
xfer->blk_num >= RC522_BLK_3){
dprintk("failed to inc_dec ctrl blk(3) data directly\n");
ret = -EINVAL;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_inc_dec_card(info,xfer);
if(ret){
dprintk("failed to inc_dec card\n");
ret = -EINVAL;
}
break;
/***** critical ops: key ops, careful !*****/
case RC522_IOC_READ_KEYA:
if(xfer->sect_num < RC522_SECT_0 ){
dprintk("failed to get used sector\n");
ret = -EINVAL;
break;
}
xfer->blk_num = RC522_BLK_3;
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
ret = gt2440_rc522_read_keya(info,xfer);
if(ret){
dprintk("failed to read key a\n");
ret = -EINVAL;
}
break;
case RC522_IOC_READ_KEYB:
if(xfer->sect_num < RC522_SECT_0 ){
dprintk("failed to get used sector\n");
ret = -EINVAL;
break;
}
xfer->blk_num = RC522_BLK_3;
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
ret = gt2440_rc522_read_keyb(info,xfer);
if(ret){dprintk("failed to read key b\n");
ret = -EINVAL;
}
break;
case RC522_IOC_READ_CTRL:
if(xfer->sect_num < RC522_SECT_0){
dprintk("failed to get used sector\n");
ret = -EINVAL;
break;
}
xfer->blk_num = RC522_BLK_3;
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
ret = gt2440_rc522_read_ctrl(info,xfer);
if(ret){
dprintk("failed to read key a\n");
ret = -EINVAL;
}
break;
/***** critical ops: keya , keyb and ctrl area write ops, careful !
****** please check the writed ctrl area using card reference menuel before do it.
****** set a lock(sect_lock) to protect sector(0-9: ctrl blk) write ops ,
****** the protected sector(0-9)'s ctrl area -using default value is ok .
****** the implement can reduce the begginner to distroy all sector using bad operation .
*****/
case RC522_IOC_WRITE_KEYA:
if(xfer->sect_num < RC522_SECT_0){
dprintk("failed to get used sector: 0x%02x\n", xfer->sect_num);
ret = -EINVAL;
break;
}
if((xfer->sect_num < CARD_LOCK_NSECT) &&
(xfer->sect_lock != RC522_SECT_UNLOCK) ){
dprintk("failed to get unlocked sector: 0x%02x\n", xfer->sect_num);
ret = -EINVAL;
break;
}
xfer->blk_num = RC522_BLK_3;
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
ret = gt2440_rc522_write_keya(info,xfer);
if(ret){dprintk("failed to write key b\n");
ret = -EINVAL;
}
break;
case RC522_IOC_WRITE_KEYB:
if(xfer->sect_num < RC522_SECT_0){
dprintk("failed to get used sector: 0x%02x\n", xfer->sect_num);
ret = -EINVAL;
break;
}
if((xfer->sect_num < CARD_LOCK_NSECT) &&
(xfer->sect_lock != RC522_SECT_UNLOCK) ){
dprintk("failed to get unlocked sector: 0x%02x\n", xfer->sect_num);
ret = -EINVAL;
break;
}
xfer->blk_num = RC522_BLK_3;
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
ret = gt2440_rc522_write_keyb(info,xfer);
if(ret){dprintk("failed to write key b\n");
ret = -EINVAL;
}
break;
case RC522_IOC_WRITE_CTRL:
if(xfer->sect_num < RC522_SECT_0){
dprintk("failed to get used sector: 0x%02x\n", xfer->sect_num);
ret = -EINVAL;
break;
}
if((xfer->sect_num < CARD_LOCK_NSECT) &&
(xfer->sect_lock != RC522_SECT_UNLOCK) ){
dprintk("failed to get unlocked sector: 0x%02x\n", xfer->sect_num);
ret = -EINVAL;
break;
}
xfer->blk_num = RC522_BLK_3;
memset(info->tx_buffer, 0x00, INFO_BUFFER_SIZE);
memset(info->rx_buffer, 0x00, INFO_BUFFER_SIZE);
ret = gt2440_rc522_auth_card(info, xfer);
if(ret){
dprintk("failed to auth card\n");
ret = -EINVAL;
break;
}
ret = gt2440_rc522_write_ctrl(info,xfer);
if(ret){dprintk("failed to write ctrl\n");
ret = -EINVAL;
}
break;
default:
dprintk("failed to get used ioc type: ioctype=%d\n", xfer->ioc_type);
ret = -EINVAL;
break;
break;
}
return ret;
}
/***** file ops function *****/
static long gt2440_rc522_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ //dprintk("gt2440_rc522_ioctl()\n");
struct gt2440_rc522_info *info;
struct spi_device *spi_dev;
struct rc522_ioc_transfer *xfer;
unsigned n_transfer;
u32 tmp = 0, offset = 0, len = 0;
int err = 0, ret = 0;
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC){
dprintk("failed to get good magic code: \n", _IOC_TYPE(cmd));
return -ENOTTY;
}
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE,
(void __user *)arg, _IOC_SIZE(cmd));
if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ,
(void __user *)arg, _IOC_SIZE(cmd));
if (err){
dprintk("failed to get read or write addr permission: \n", err);
return -EFAULT;
}
info = filp->private_data;
spin_lock_irq(&info->spi_lock);
spi_dev = spi_dev_get(info->spi_dev);
spin_unlock_irq(&info->spi_lock);
if (spi_dev == NULL){
dprintk("failed to get alive spi device : \n");
return -ESHUTDOWN;
}
mutex_lock(&info->buf_lock);
switch (cmd) {
default:
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
|| _IOC_DIR(cmd) != _IOC_WRITE) {
dprintk("failed to get used massage : \n");
ret = -ENOTTY;
break;
}
tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct rc522_ioc_transfer)) != 0) {
dprintk("failed to get aligned massage : \n");
ret = -EINVAL;
break;
}
n_transfer = tmp / sizeof(struct rc522_ioc_transfer);
if (n_transfer == 0 || n_transfer > 1){
dprintk("failed to support more massage : \n");
ret = -EINVAL;
break;
}
xfer = kmalloc(tmp, GFP_KERNEL);
if (!xfer) {
dprintk("failed to allocate struct rc522_ioc_transfer{}: \n");
ret = -ENOMEM;
break;
}
if (__copy_from_user(xfer, (void __user *)arg, tmp)) {
dprintk("failed to copy k space from u space: \n");
kfree(xfer);
ret = -EFAULT;
break;
}
ret = gt2440_rc522_pass_op(info, xfer);
if(ret){
dprintk("failed to pass operation\n");
ret = -EFAULT;
}else{
switch(xfer->ioc_type){
case RC522_IOC_REQ_CARD:
case RC522_IOC_READ_CARD:
case RC522_IOC_READ_KEYA:
case RC522_IOC_READ_KEYB:
case RC522_IOC_WRITE_KEYA: /*return old value*/
case RC522_IOC_WRITE_KEYB:
case RC522_IOC_READ_CTRL:
case RC522_IOC_WRITE_CTRL:
//len = tmp;
len = CARD_ID_SIZE + CARD_BLK_SIZE + CARD_PLUS_SIZE;
offset = (tmp - len);
if(__copy_to_user((u8 __user *)(arg)+offset,
((u8 *)xfer) + offset,
len )){
dprintk("failed to copy k space to u space: \n");
ret = -EFAULT;
}
break;
default :
break;
}
;;;
}
kfree(xfer);
break;
/***** spi inferface mode set *****/
case SPI_IOC_RD_MODE:
ret = __put_user(spi_dev->mode & SPI_MODE_MASK,(__u8 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
ret = __put_user((spi_dev->mode & SPI_LSB_FIRST) ? 1 : 0,(__u8 __user *)arg);
break;
case SPI_IOC_RD_BITS_PER_WORD:
ret = __put_user(spi_dev->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
ret = __put_user(spi_dev->max_speed_hz, (__u32 __user *)arg);
break;
case SPI_IOC_WR_MODE:
ret = __get_user(tmp, (u8 __user *)arg);
if (ret == 0) {
u8 save = spi_dev->mode;
if (tmp & ~SPI_MODE_MASK) {
ret = -EINVAL;
break;
}
tmp |= spi_dev->mode & ~SPI_MODE_MASK;
spi_dev->mode = (u8)tmp;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->mode = save;
else
dev_dbg(&spi_dev->dev, "spi mode %02x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
ret = __get_user(tmp, (__u8 __user *)arg);
if (ret == 0) {
u8 save = spi_dev->mode;
if (tmp)
spi_dev->mode |= SPI_LSB_FIRST;
else
spi_dev->mode &= ~SPI_LSB_FIRST;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->mode = save;
else
dev_dbg(&spi_dev->dev, "%csb first\n",tmp ? 'l' : 'm');
}
break;
case SPI_IOC_WR_BITS_PER_WORD:
ret = __get_user(tmp, (__u8 __user *)arg);
if (ret == 0) {
u8 save = spi_dev->bits_per_word;
spi_dev->bits_per_word = tmp;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->bits_per_word = save;
else
dev_dbg(&spi_dev->dev, "%d bits per word\n", tmp);
}
break;
case SPI_IOC_WR_MAX_SPEED_HZ:
ret = __get_user(tmp, (__u32 __user *)arg);
if (ret == 0) {
u32 save = spi_dev->max_speed_hz;
spi_dev->max_speed_hz = tmp;
ret = spi_setup(spi_dev);
if (ret < 0)
spi_dev->max_speed_hz = save;
else
dev_dbg(&spi_dev->dev, "%d Hz (max)\n", tmp);
}
break;
}
mutex_unlock(&info->buf_lock);
spi_dev_put(spi_dev);
return ret;
}
static int gt2440_rc522_open(struct inode *inode, struct file *filp)
{ //dprintk("gt2440_rc522_open()\n");
struct gt2440_rc522_info *info;
int ret = -ENXIO;
mutex_lock(&device_list_lock);
list_for_each_entry(info, &device_list, device_entry) {
if (info->devt == inode->i_rdev) {
ret = 0;
break;
}
}
if (ret == 0) {
if(info->users == 0){
/*
hardware power up mode:
gt2440_rc522_hardup_chip();
software power up mode:
gt2440_rc522_softup_chip();
*/
if(ret = gt2440_rc522_init_chip(info)){
dev_err(&info->spi_dev->dev, "failed to open rc522\n");
/*
software power down mode:
gt2440_rc522_softop_chip();
hardware power down mode:
gt2440_rc522_hardop_chip();
*/
}
}
info->users++;
filp->private_data = info;
nonseekable_open(inode, filp);
} else
pr_debug("rc522: nothing for minor %d\n", iminor(inode));
mutex_unlock(&device_list_lock);
return ret;
}
static int gt2440_rc522_release(struct inode *inode, struct file *filp)
{ //dprintk("gt2440_rc522_release()\n");
struct gt2440_rc522_info *info;
int ret = 0;
mutex_lock(&device_list_lock);
info = filp->private_data;
filp->private_data = NULL;
info->users--;
if (!info->users) {
/*
software power down mode:
gt2440_rc522_softop_chip();
hardware power down mode:
gt2440_rc522_hardop_chip();
*/
int dofree;
spin_lock_irq(&info->spi_lock);
dofree = (info->spi_dev == NULL);
spin_unlock_irq(&info->spi_lock);
if (dofree) kfree(info);
}
mutex_unlock(&device_list_lock);
return info;
}
/***** probe and remove function ****/
#ifdef GT2440_RC522_TEST
void gt2440_rc522_test_card(struct gt2440_rc522_info *info)
{
/* only for test mode, normal mode will remove follow code */
gt2440_rc522_init_chip(info);
int i = 2;
int ret = 0;
struct rc522_ioc_transfer xfer={
.key_type = RC522_KEY_A,
.sect_num = RC522_SECT_15,
.blk_num = RC522_BLK_0,
};
for(i = 0; i<CARD_KEYA_SIZE; i++){
xfer.keya_buf[i] = (u8)0xff;
xfer.keyb_buf[i] = (u8)0xff;
}
while(i--){
ret = gt2440_rc522_request_card(info, &xfer);
if(ret ){
dev_err(&info->spi_dev->dev, "failed to request card\n");
}else{
dev_info(&info->spi_dev->dev,
"good to request card: 0x%02x, 0x%02x\n",
xfer.txrx_buf[0], xfer.txrx_buf[1]);
break;
}
msleep(50);
}
if(i == 0){
return ;
}
// rc522 spi1.0: good to anticoll card : 0x30, 0x93, 0xb7, 0x4f, 0x00
ret = gt2440_rc522_anticoll_card(info, &xfer);
if(ret ){
dev_err(&info->spi_dev->dev, "failed to anticoll card\n");
}else{
dev_info(&info->spi_dev->dev,
"good to anticoll card : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
xfer.txrx_buf[2], xfer.txrx_buf[3],
xfer.txrx_buf[4], xfer.txrx_buf[5], xfer.txrx_buf[6]);
}
ret = gt2440_rc522_select_card(info, &xfer);
if(ret){
dev_err(&info->spi_dev->dev, "failed to select card\n");
}else{
memcpy(xfer.id_buf, &xfer.txrx_buf[CARD_TYPE_SIZE], CARD_ID_SIZE);
dev_info(&info->spi_dev->dev,
"good to select card: \n"
"type = 0x%02x, 0x%02x\n"
"id = 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n"
"capacity = 0x%02x Kbits, 0x%02x, 0x%02x\n",
xfer.txrx_buf[0], xfer.txrx_buf[1],
xfer.txrx_buf[2], xfer.txrx_buf[3],
xfer.txrx_buf[4], xfer.txrx_buf[5],
xfer.txrx_buf[6],
xfer.txrx_buf[7],
xfer.txrx_buf[8], xfer.txrx_buf[9]);
}
msleep(50);
dprintk("1 Read Card:");
ret = gt2440_rc522_auth_card(info, &xfer);
if(ret ){
dev_err(&info->spi_dev->dev, "failed to auth card\n");
}else{
dev_info(&info->spi_dev->dev,
"good to auth card: \n");}
ret = gt2440_rc522_read_card(info, &xfer);
if(ret ){
dev_err(&info->spi_dev->dev, "failed to read card\n");
}else{
dev_info(&info->spi_dev->dev,
"good to read card: ");
dprintk("sect=0x%02x, blk=0x%02x\n",xfer.sect_num, xfer.blk_num );
for(i = 0; i< CARD_BLK_SIZE+CARD_PLUS_SIZE; i++){
if(i%4 == 0) dprintk("\n");
dprintk("0x%02x ",xfer.txrx_buf[i] );
}
dprintk("\n");
}
dprintk("\n");
dprintk("\nwill write card: 0x%02x, 0x%02x\n",xfer.sect_num, xfer.blk_num );
for(i = 0; i<CARD_BLK_SIZE; i++){
if(i%4 == 0)dprintk("\n");
dprintk("0x%02x ", i);
xfer.txrx_buf[i]= (unsigned char) i;
}
dprintk("\n");
ret = gt2440_rc522_write_card(info, &xfer);
if(ret ){dev_err(&info->spi_dev->dev, "failed to read card\n");
}else{dev_info(&info->spi_dev->dev, "good to write card: ");
dprintk("sect=0x%02x, blk=0x%02x\n",xfer.sect_num, xfer.blk_num );
for(i = 0; i< CARD_BLK_SIZE; i++){
if(i%4 == 0)dprintk("\n");
dprintk("0x%02x ",xfer.txrx_buf[i] );
}dprintk("\n");
}
msleep(50);
dprintk("2 Read Card:");
ret = gt2440_rc522_auth_card(info, &xfer);
if(ret ){
dev_err(&info->spi_dev->dev, "failed to auth card\n");
}else{
dev_info(&info->spi_dev->dev,
"good to auth card: \n");}
ret = gt2440_rc522_read_card(info, &xfer);
if(ret ){
dev_err(&info->spi_dev->dev, "failed to read card\n");
}else{
dev_info(&info->spi_dev->dev,
"good to read card: ");
dprintk("sect=0x%02x, blk=0x%02x\n",xfer.sect_num, xfer.blk_num );
for(i = 0; i< CARD_BLK_SIZE+CARD_PLUS_SIZE; i++){
if(i%4 == 0) dprintk("\n");
dprintk("0x%02x ",xfer.txrx_buf[i] );
}
dprintk("\n");
}
}
#else
void gt2440_rc522_test_card(struct gt2440_rc522_info *info){}
#endif
static int gt2440_rc522_probe(struct spi_device *spi_dev)
{ dprintk("gt2440_rc522_probe()\n");
struct gt2440_rc522_info *info;
unsigned long minor;
int ret;
info = kzalloc(sizeof(struct gt2440_rc522_info), GFP_KERNEL);
if (info == NULL) {
dev_err(&spi_dev->dev,"failed to allocate struct gt2440_rc522_info{}\n");
return -ENOMEM;
}
info->spi_dev = spi_dev;
INIT_LIST_HEAD(&info->device_entry);
spin_lock_init(&info->spi_lock);
mutex_init(&info->buf_lock);
spi_set_drvdata(spi_dev, info);
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;
info->devt = MKDEV(SPICHAR_MAJOR, minor);
dev = device_create(gt2440_rc522_class, &spi_dev->dev, info->devt,
info, "rc522-%d.%d",
spi_dev->master->bus_num, spi_dev->chip_select);
if(IS_ERR(dev)){
dev_dbg(&spi_dev->dev, "failed to create device \n");
ret = IS_ERR(dev) ;
goto exit_1;
}
} else {
dev_err(&spi_dev->dev, "failed to allocate minor number \n");
ret = -ENODEV;
goto exit_1;
}
set_bit(minor, minors);
list_add(&info->device_entry, &device_list);
mutex_unlock(&device_list_lock);
/*
software power down mode:
gt2440_rc522_softop_chip();
hardware power down mode:
gt2440_rc522_hardop_chip();
*/
gt2440_rc522_test_card(info);
return 0;
exit_1:
kfree(info);
spi_set_drvdata(spi_dev, NULL);
return ret;
}
static int gt2440_rc522_remove(struct spi_device *spi_dev)
{ dprintk("gt2440_rc522_remove()\n");
struct gt2440_rc522_info *info = spi_get_drvdata(spi_dev);
if(info == NULL) return 0;
spin_lock_irq(&info->spi_lock);
info->spi_dev = NULL;
spi_set_drvdata(spi_dev, NULL);
spin_unlock_irq(&info->spi_lock);
mutex_lock(&device_list_lock);
list_del(&info->device_entry);
device_destroy(gt2440_rc522_class, info->devt);
clear_bit(MINOR(info->devt), minors);
if (info->users == 0) kfree(info);
mutex_unlock(&device_list_lock);
/*
software power down mode:
gt2440_rc522_softop_chip();
hardware power down mode:
gt2440_rc522_hardop_chip();
*/
return 0;
}
/***** spi board info and spi driver structure ****/
static struct spi_board_info gt2440_spi_board_info = {
.modalias = SPI_DEVICE_NAME, /* rc522 != spidev*/
//.irq = IRQ_EINT4,
.max_speed_hz = 500*1000,
.bus_num = 1,
.chip_select = 0,
.mode = SPI_MODE_0,
};
static struct spi_driver gt2440_rc522_spi_driver = {
.driver = {
.name = SPI_DEVICE_NAME, /* rc522 != spidev*/
.owner = THIS_MODULE,
},
.probe = gt2440_rc522_probe,
.remove = gt2440_rc522_remove,
};
/***** init and exit ****/
static int __init gt2440_rc522_init(void)
{ dprintk("gt2440_rc522_init()\n");
int ret;
BUILD_BUG_ON(N_SPI_MINORS > 256);
ret = register_chrdev(SPICHAR_MAJOR, SPI_DEVICE_NAME, &gt2440_rc522_fops);
if (ret < 0){
printk(KERN_ERR"failed to register char device\n");
return ret;
}
gt2440_rc522_class = class_create(THIS_MODULE, SPI_DEVICE_NAME);
if (IS_ERR(gt2440_rc522_class)) {
printk(KERN_ERR"failed to create class\n");
ret = PTR_ERR(gt2440_rc522_class);
goto exit_1;
}
/***** find spi_master from system by bus_num, then create spi_device .
****** if you insert module again,
****** the kernel spi subsystem will make a bug(selectchip busy error).
****** the follow code can reduce the bug, and get more help for debug .
****** the condition is kernel has spi master driver surpport .
*****/
master = spi_busnum_to_master(gt2440_spi_board_info.bus_num);
if(IS_ERR(master)){
printk(KERN_ERR"failed to find spi master \n");
ret = PTR_ERR(gt2440_rc522_class);
goto exit_2;
}
spi = spi_new_device(master, &gt2440_spi_board_info);
if(IS_ERR(master)){
printk(KERN_ERR"failed to create spi device \n");
ret = PTR_ERR(gt2440_rc522_class);
goto exit_3;
}
/***** end *****/
ret = spi_register_driver(&gt2440_rc522_spi_driver);
if (ret < 0) {
printk(KERN_ERR"failed to register spi driver\n");
goto exit_4;
}
return 0;
exit_4:
spi_unregister_device(spi);
spi = NULL;
exit_3:
put_device(&master->dev);
master = NULL;
exit_2:class_destroy(gt2440_rc522_class);
gt2440_rc522_class = NULL;
exit_1:
unregister_chrdev(SPICHAR_MAJOR,
gt2440_rc522_spi_driver.driver.name);
return ret;
}
static void __exit gt2440_rc522_exit(void)
{ dprintk("gt2440_rc522_exit()\n");
spi_unregister_driver(&gt2440_rc522_spi_driver);
if(spi != NULL)
spi_unregister_device(spi);
if(master != NULL)
put_device(&master->dev);
class_destroy(gt2440_rc522_class);
unregister_chrdev(SPICHAR_MAJOR,
gt2440_rc522_spi_driver.driver.name);
}
module_init(gt2440_rc522_init);
module_exit(gt2440_rc522_exit);
MODULE_DESCRIPTION("GT2440 RC522 SPI Device Driver");
MODULE_AUTHOR("Liguang13579<[email protected]>");
MODULE_LICENSE("GPL v2");
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/jzhiyu/Linux-RC522-SPI-S50-Read-Card-Device-Drivers.git
[email protected]:jzhiyu/Linux-RC522-SPI-S50-Read-Card-Device-Drivers.git
jzhiyu
Linux-RC522-SPI-S50-Read-Card-Device-Drivers
Linux RC522 SPI S50 Read Card Device Drivers
master

搜索帮助