磁条卡驱动

这是一个Linux内核驱动程序,用于处理磁条卡读取。驱动通过GPIO引脚控制SPI接口,读取卡上的数据并进行校验。驱动包括中断处理、数据转换以及错误检查功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 *   MSR driver
 *       
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fcntl.h> 
#include <linux/fs.h>   
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/jiffies.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>


#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/atomic.h>


#include <asm/irq.h>
#include <mach/reg_gpio.h>
#include <mach/hardware.h>
#include <linux/strong_lion_def.h> 


#include "msr.h"
//#include "version.h"


unsigned long schedule_delayed_work_time = 0;
struct delayed_work delay_work;
static struct proc_dir_entry *msr_ver;


char *kbuf =NULL;
int kbuf_size=245;


#define SPI_DELAY udelay(30)
#define SPI_MO_HIGH reg_gpio_set_pin( BCM5892_GPB9, 1)
#define SPI_MO_LOW reg_gpio_set_pin( BCM5892_GPB9, 0)
#define SPI_CLK_HIGH reg_gpio_set_pin( BCM5892_GPB14, 1)
#define SPI_CLK_LOW reg_gpio_set_pin( BCM5892_GPB14, 0)
#define SPI_MI (readl(IO_ADDRESS(GIO1_REG_BASE_ADDR+REGOFFSET_GPIO_IOTR + 0x800)) & (1<<10))
#define SPI_DAV_VALID (readl(IO_ADDRESS(GIO1_REG_BASE_ADDR+REGOFFSET_GPIO_IOTR + 0x800)) & (1<<26))
#define READ_NUM  264
int msr_irq;
static int interrupt_en = 0;
static struct completion data_done;
int ask_read = 0;   


//the flag used by noblock read;
enum read_status {NO_READ, WAIT, READY };


#define MAX_TRACK_DATA_BYTES 120 //108
#define MAX_TRACK_BITS (264*8)
#define MCR_END_SENTINEL 0x3F




unsigned int tracks_abc_len[NUM_MCR_TRACKS];// Number of bytes of data on each track
static int ideal_time = 10;




volatile enum read_status msr_read_flag = NO_READ;


#define MCR_HAVEOPENED 1
#define MCR_NOT_HAVEOPENED 0
static atomic_t  HaveOpen = ATOMIC_INIT(MCR_NOT_HAVEOPENED);




static unsigned char cal_lrc(unsigned char *p, unsigned int len)
{
    return 0;
/*
unsigned char lrc=0;
unsigned int i;
for(i=0; i<len; i++)
{
lrc ^= p[i];
}


    printk("calculated lrc[%02x]\n", lrc);
return lrc;
*/
}






static int whether_track_data_is_ok(char *track, int len, int track_no)
{
  printk("that time track[%d]--len[%d]\n[%s]\n", track_no, len, track);


// 1. LRC
if(cal_lrc(track, len))
{
        printk("lrc failed!\n");
return -1;
}
        printk("lrc ignore!\n");


// 2. delimiter char  
if('?' != track[len-2])
{
        printk("no end char!\n");
return -1; 
}
if(1 == track_no)
{
if('%' != track[0])
{

        printk("no start char % !\n");
return -1; 
}
}
else
{
if(';' != track[0])
{
         printk("no start char ; !\n");
return -1; 
}
}


if(len < 4)
{
     printk("maybe wrong??? no real data!\n");
return -1;
}
// 3. Length
if(((1 == track_no) && (len > 79)) ||
((2 == track_no) && (len > 40)) ||
((3 == track_no) && (len > 107)))
{
      printk("wrong length!\n");
return -1; 
}


     printk("check OKAY!\n");
return 0;
}






static int all_is_zero(unsigned char *data, int len)
{
int i;


for(i=0;i<len;i++)
{
if (*(data+i))
return 0;//data space(char arry) not all is 0
}


return 1;
}




static unsigned int bin_to_chars(unsigned char * pBin,unsigned char * pTrkData,
                                         unsigned int uiCount, int track_no)
{
unsigned int iLoop, iLp;
unsigned int uiByteCount = 0;
unsigned char cbValue;
unsigned char  cbParity;/*cb is char bin*/
unsigned char cbLRC = 0;
unsigned int uiIs7BitFW = 0;
unsigned int uiIs5BitFW = 0;
unsigned char start_tag, real_tag;
int code_size;
int cnt=0;
char found_start=0;
    char *p_track=pTrkData;


if(1 == track_no)/*array index,here are two kind of data format,they have differnt 
                              start_tag and code_size*/
{
uiIs7BitFW = 1;    //track1
start_tag = 0x45;/*it similar to the flag of start bit ,but it just use a char instead of a bit
so we should check the real_tag ,whether it is the same value of start_tag*/
code_size = 7;
}
else
{
uiIs5BitFW = 1;
start_tag = 0x0B;
code_size = 5;
}
real_tag = 0;
//find the start tag
while(cnt < uiCount)
{
real_tag >>= 1;
/*if pBin="00(01000101)00001011010"we can see start_tag =0x45 is at (01000101)
so the following code is to get the value of the pbin,when it moves to the end of(01000101),
real_tag == start_tag will be true,so we can get the pBin=pbin+10(cnt)-7,*/


/* pBin[cnt] is char(0 or 1)not('1',or'0'),<<6 is fixed ,but real_tag is moving,
 * we will only get the low 7 bits of real_tag
 */
real_tag |= (pBin[cnt++]<<(code_size-1));
if(real_tag == start_tag)
{
   printk("track_no:%d,start_tag:%d\n",track_no,start_tag);
found_start = 1;
pBin += (cnt-code_size);
break;
}
}


if(!found_start)
{
      //  printk( "No start tag detected!\n" );
return 0;
}


if( uiIs7BitFW )
{
for( iLoop=0; iLoop<uiCount; iLoop+=7 )
{
cbValue = 0;
cbParity = 1;
for( iLp=0; iLp<6; iLp++ )/*read out the track's 7 bytes data(they are all 0 or 1)*/
{
cbValue =cbValue | (*pBin << iLp);/*although *pBbin looks like a bit , the data on the track
is saved in char 0 or 1(not '0' or '1' too),rather than a bit 0 or 1*/
cbParity ^= *pBin++;/*异或,奇数个1,则校验标志为0
偶数个1,校验标志为 1*/
}
if( cbParity == *pBin++ )/*compare the cbParity with the end data(data parity bit)*/

   // Good Value
   /*convert raw data to ASCII code ,we should add 0x20 to the 6 bits data*/
*pTrkData++ = cbValue + 0x20;
cbLRC ^= cbValue;/*==   cbLRC = cbValue;*/
uiByteCount++;


/* No need to process past ES + valid LRC */
if(  (*(pTrkData-2) == MCR_END_SENTINEL) )
{
//printk( "break here[%d]!\n", uiByteCount);
break;
}
}
}
}

if( uiIs5BitFW )
{
for( iLoop=0; iLoop<uiCount; iLoop+=5 )
{
cbValue = 0;
cbParity = 1;
for( iLp=0; iLp<4; iLp++ )
{
cbValue = cbValue | (*pBin << iLp);
cbParity ^= *pBin++;
}
if( cbParity == *pBin++ )

   // Good Value
   /*convert raw data to ASCIIcode ,we should add 0x30 to the 4 bits data*/
*pTrkData++ = cbValue + 0x30;//it is 48,convert number to char
cbLRC ^=cbValue;
uiByteCount++;


/* No need to process past ES + valid LRC */
if( (*(pTrkData-2) == MCR_END_SENTINEL) )
{
               //  printk( "break here line[%d] [%d]!\n",  __LINE__, uiByteCount);
break;
}
}
}
}


/* Verify LRC    */
if( cbLRC != 0 )
{
        p_track[uiByteCount] = 0;//LRC fail. uiByteCount[%d]\n    ,uiByteCount,
       // printk("[%s]\n", p_track);
uiByteCount = 0;
}


return( uiByteCount );
}




static inline  void enable_mcr_int(void)
{
if (!interrupt_en)
{
interrupt_en = 1;
reg_gpio_enable_interrupt( BCM5892_GPB26 );
}
}


static inline void disable_mcr_int(void)
{
if (interrupt_en )
{
interrupt_en = 0;
reg_gpio_disable_interrupt( BCM5892_GPB26 );
}
}


inline static void enable_spi(void)
{
reg_gpio_set_pin( BCM5892_GPB13, 0);
}


inline static void disable_spi(void)
{
reg_gpio_set_pin( BCM5892_GPB13, 1);
}


static void spi_senddata(unsigned char ucData)
{
int i;


enable_spi();    //cs validate
SPI_DELAY;

for(i=0;i<8;i++)
{
if(ucData & 0x80) 
SPI_MO_HIGH;
else
SPI_MO_LOW;
ucData<<=1;

//clk serial numbers
SPI_DELAY;
SPI_CLK_HIGH; 
SPI_DELAY;   
SPI_CLK_LOW;  
}

SPI_DELAY;
SPI_MO_HIGH;
disable_spi();


//udelay(30);
}


static void spi_revdata(unsigned char *pData)
{
int i;
unsigned char tch;

enable_spi();
tch=0;
for(i=0;i<8;i++)
{
SPI_DELAY;
SPI_CLK_HIGH;

tch<<=1;
if (SPI_MI) 
tch|=1;

SPI_DELAY;
SPI_CLK_LOW;
}

*pData=tch;
tch=0;

SPI_DELAY;


disable_spi();


udelay(30);

}






static void spi_revdata264(unsigned char*tmp)
{
int j,i;
unsigned char tch;

enable_spi();

for(i=0;i<READ_NUM;++i)
{
tch=0;
for(j=0;j<8;++j)
{
SPI_DELAY;
SPI_CLK_HIGH;

tch<<=1;
if (SPI_MI) 
tch|=1;

SPI_DELAY;
SPI_CLK_LOW;
}

SPI_DELAY;
tmp[i]=tch;


}
disable_spi();


udelay(30);
return;

}








static int check_direct_decode(char*bin_tmp_buf,char**parray)
{
int i=0,ret=0;

for(i=0;i<3;i++)
{
if(whether_track_data_is_ok(parray[i], tracks_abc_len[i] , i+1))
{
  ret+=1;
}
}
if(ret<3)
ret=0;
return ret;
}


static int reverse_track(int no,char*bin_tmp_buf,char*p)
{
unsigned char tmp=0;
int k=0;


for(k=0; k<(READ_NUM*8)/2; k++)
{
tmp = bin_tmp_buf[no*MAX_TRACK_BITS+k];
bin_tmp_buf[no*MAX_TRACK_BITS+k] =bin_tmp_buf[no*MAX_TRACK_BITS+READ_NUM*8-1-k];
bin_tmp_buf[no*MAX_TRACK_BITS+READ_NUM*8-1-k] = tmp;
}




tracks_abc_len[no] = bin_to_chars( (unsigned char *)(&bin_tmp_buf[no*MAX_TRACK_BITS+(READ_NUM/3-2)*no*8]), p, READ_NUM/3*8, no+1);




return 0;
}




static int reverse_char_array_then_reparse(char*bin_tmp_buf,char**parray)
{
int i=0;

for(i=0;i<3;++i)
{
reverse_track(i,bin_tmp_buf,parray[i]);
}
return 0;


}






static int direct_decode(char* bin_tmp_buf,char**parray)
{
int i=0;

for(i=0;i<3;++i)
{
tracks_abc_len[i] = bin_to_chars( (unsigned char *)(&bin_tmp_buf[(2-i)*MAX_TRACK_BITS+(2-i)*(READ_NUM/3)*8]), parray[i], READ_NUM/3*8, i+1);
}
return (tracks_abc_len[0]+tracks_abc_len[1]+tracks_abc_len[2]);
}
static char* read_raw_data()
{
int i=0,j=0,count=0;
unsigned char *tmp = kzalloc(READ_NUM,GFP_KERNEL);
if(!tmp){
printk("failed to kzalloc tmp\n");
return -EINVAL;
}

char* bin_tmp_buf = kzalloc(MAX_TRACK_BITS*NUM_MCR_TRACKS,GFP_KERNEL);
if(!bin_tmp_buf){
printk("failed to kzalloc bin_tmp_buf\n");
return -EINVAL;
}
printk("MSR read_raw_data_to_char_bit_array\n");

SPI_MO_HIGH;
spi_revdata264(tmp);

//if  error reverse scape error deal
if(tmp[READ_NUM-1]==1)
{
for(i=READ_NUM-1;i>=1;i--)
{
tmp[i]=tmp[i]>>1;
if(tmp[i-1]&0x01==1)
tmp[i]|=0x80;
else 
tmp[i]&=0x7f;
}
 
}


for(i=0;i<READ_NUM;i++)
{
for(j=0;j<3;j++)
{
   for(count=0;count<8;count++)
   {
    if((tmp[i]<<count) & 0x80)
    {
    bin_tmp_buf[j*MAX_TRACK_BITS+i*8+count]=1;
    }
else
{
bin_tmp_buf[j*MAX_TRACK_BITS+i*8+count]=0;
}


   }
}
       
}



kfree(tmp);
return bin_tmp_buf;
}


static int msr_interrupt_work_deal()
{
int ret=0,len=0,retval=0;
char *bin_tmp_buf=NULL;
char* parray[3]={0};//数组中的每一个指针都指向3个磁道的空间
parray[0]=kzalloc(MAX_TRACK_DATA_BYTES,GFP_KERNEL);
parray[1]=kzalloc(MAX_TRACK_DATA_BYTES,GFP_KERNEL);
parray[2]=kzalloc(MAX_TRACK_DATA_BYTES,GFP_KERNEL);


kbuf = kzalloc(kbuf_size,GFP_KERNEL);
/*if(   !(  parray[0] && parray[1] && parray[2] && kbuf   )    )*/
if((!parray[0]) || (!parray[1]) || (!parray[2])||(!kbuf)){
printk("failed to kzalloc tracks memeory\n");
retval = -EINVAL;
goto out;
}


bin_tmp_buf = read_raw_data();

direct_decode(bin_tmp_buf,parray);

ret=check_direct_decode(bin_tmp_buf,parray);

if(ret)
{
reverse_char_array_then_reparse(bin_tmp_buf,parray);
}
for(ret=0;ret<3;ret++)
{
len += sprintf(kbuf+len,"track%d:%s\n",ret+1,parray[ret]);
}

if (msr_read_flag == WAIT)//for nonblocked-read
{
msr_read_flag = READY;
}
else //for blocked-read
{
complete(&data_done);
}

disable_mcr_int();
out:
kfree(bin_tmp_buf);
for(ret=0;ret<3;ret++)
{
kfree(parray[ret]);
}

return retval;
}






static irqreturn_t  msr_interrupt(int irq,void * dev_id)
 {
int dav_val =0;
//printk("msr_interrupt\n");//do not use printk in interrupt function.
ndelay(10);
reg_gpio_disable_interrupt( BCM5892_GPB26 );
reg_gpio_clear_interrupt( BCM5892_GPB26 );
dav_val = reg_gpio_get_pin( BCM5892_GPB26);//high level valid means we have striped

if (dav_val)
{
if (!ask_read)
return IRQ_HANDLED;
schedule_delayed_work(&delay_work,
schedule_delayed_work_time);
}


return IRQ_HANDLED;
}








static int proc_read_msr_ver(char *page,char **start,off_t off, 
int count,int *eof,void *data)
{
int len=0;
#if 0
len = sprintf(page, "%s%s\n", ID_SCL_VERSION,SCL_VERSION);
len += sprintf(page+len,"%s%s\n",ID_MACHINE,MACHINE);
len += sprintf(page+len,"%s%s\n", ID_COMPILE_TIME,COMPILE_TIME);
len += sprintf(page+len,"%s%s\n", ID_COMPILE_BY,COMPILE_BY);
len += sprintf(page+len,"%s%s\n", ID_COMPILE_HOST,COMPILE_HOST);
len += sprintf(page+len,"%s%s\n", ID_COMPILE_DOMAIN,COMPILE_DOMAIN);
len += sprintf(page+len,"%s%s\n", ID_COMPILER,COMPILER);
len += sprintf(page+len,"%s%d\n", ID_KERNEL_VERSION,KERNEL_VERSION);


#endif
*eof = 1;
return len;
}


static  int msr_open(struct inode *inode, struct file *filp)   
{printk("i have entered open func\n");
if (MCR_HAVEOPENED == atomic_read(&HaveOpen))
{
return -EBUSY;
}
printk("see you\n");
atomic_set(&HaveOpen,MCR_HAVEOPENED);


msr_read_flag = NO_READ;
ask_read = 0;
init_completion(&data_done); 


  return 0;
}




static ssize_t msr_read(struct file *filp, char   *buf, size_t count,loff_t *f_pos)
{
int iRet = 0;
unsigned long dead_line;


     //none_block read
if (filp->f_flags & O_NONBLOCK)
{
if (msr_read_flag == NO_READ)
{
msr_read_flag = WAIT;/*if msr_read_flag is no_read ,so we change it to wait ,and interrupt*/
enable_mcr_int();/*interrupt*/
ask_read = 1;//要读却没有读的请求读标志

iRet = -EAGAIN;
goto out1;
}
else if(msr_read_flag == WAIT)//非阻塞不能等
{
iRet = -EAGAIN;
goto out1;
}
else if(msr_read_flag == READY)
{
msr_read_flag = NO_READ;//此时不能再让其他的读的进程打扰,所以将标志变为不可读

goto cont1;/*deal with a normal read*/
}
else 
printk("unknow read mcr status\n");
}

ask_read = 1;/*before read is normal ,we need a ask_read flag =1(request flag),
                      and after interrupt and wait ,read will be ok,
                      when it is ok ,we should set ask_read flag = 0*/


enable_mcr_int();


wait_for_completion(&data_done);


/*process mcr sample data
 *shutdown all mcr interrupt and disable mcr dma to avoid that 
 *new swipe and  interrput  occur when process the sample data.
 */
cont1:


ask_read = 0;
//恢复GPIO为中断方式
reg_gpio_set_pull_up_down_enable(BCM5892_GPB26);
reg_gpio_iotr_set_pin_type(BCM5892_GPB26,GPIO_PIN_TYPE_INPUT_WITH_INTERRUPT);

//copy the track data to user
if (copy_to_user(buf, kbuf, kbuf_size))//keep mind that as to a pointer,sizeof(pointer)=4;
{
printk("copy track data to user fail. \n");

goto done;
}


done:

/*
* delay a tiny time before return to user
* avoid the error of the MCR !! 
*/
dead_line = jiffies + (ideal_time *HZ) /1000;
while( time_before(jiffies, dead_line) )
schedule();/*before the time arrive ,we use schedule() to do something else
   when time arrive ,schedule() will return */


out1:
kfree(kbuf);
return (iRet);/*read  bytes number*/
}






static int msr_release(struct inode *inode, struct file *filp)
{
printk("mcr_release \n");


disable_mcr_int();


atomic_set(&HaveOpen,MCR_NOT_HAVEOPENED);


    return 0;
}


static ssize_t msr_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
unsigned char ch;
printk("\n\n enter ...ttidev_write !!\n");
printk("Buffer=[%s]\n",buf);
if(copy_from_user(&ch,buf,1)!=0)
{
printk("copy_from_usr failed!\n");
return -1;
    }
spi_senddata(0x90);
    udelay(50);
// SPI_MO_HIGH;
    spi_senddata(0xff);
spi_revdata(&ch);
printk("ch:%d\n",ch);//0x4d

return 0;
}


static int msr_ioctl(struct inode *inode,struct file *filp,unsigned int cmd, unsigned long arg)
{

return 0;
}


static struct cdev mcr_cdev;


struct file_operations  mcr_fops=
{
.owner = THIS_MODULE,
.read = msr_read,
.write = msr_write,
.open = msr_open,
.release = msr_release,
.ioctl = msr_ioctl,
};


//the used pin
/*
SPI_CLK :GPB14
SPI_MISO :GPB10
SPI_MOSI :GPD9
SPI_DAV :GPB26
SPI_CS :GPD13
*/
static void hardware_init(void)
{
//SPI_CLK,模式 0下为低电平
reg_gpio_set_pull_up_down_enable(BCM5892_GPB14);/* pull-up/down enable */
reg_gpio_set_pull_up_down(BCM5892_GPB14, 1);
reg_gpio_iotr_set_pin_type(BCM5892_GPB14,GPIO_PIN_TYPE_OUTPUT);//output
reg_gpio_set_pin( BCM5892_GPB14, 0);


//SPI_MISO
reg_gpio_set_pull_up_down_enable(BCM5892_GPB10);/* pull-up/down enable */
reg_gpio_set_pull_up_down(BCM5892_GPB10, 1);
reg_gpio_iotr_set_pin_type(BCM5892_GPB10,GPIO_PIN_TYPE_INPUT);//input


//SPI_MOSI
reg_gpio_set_pull_up_down_enable(BCM5892_GPB9);/* pull-up/down enable */
reg_gpio_set_pull_up_down(BCM5892_GPB9, 1);
reg_gpio_iotr_set_pin_type(BCM5892_GPB9,GPIO_PIN_TYPE_OUTPUT);//output
reg_gpio_set_pin( BCM5892_GPB9, 0);


//SPI_CS
reg_gpio_set_pull_up_down_enable(BCM5892_GPB13);/* pull-up/down enable */
reg_gpio_set_pull_up_down(BCM5892_GPB13, 1);
reg_gpio_iotr_set_pin_type(BCM5892_GPB13,GPIO_PIN_TYPE_OUTPUT);//output
reg_gpio_set_pin( BCM5892_GPB13, 1);//don't enable MSR


//SPI_DAV ,中断方式
reg_gpio_set_pull_up_down_enable(BCM5892_GPB26);
reg_gpio_set_pull_up_down(BCM5892_GPB26, 1);

reg_gpio_disable_interrupt( BCM5892_GPB26 );
reg_gpio_iotr_set_pin_type(BCM5892_GPB26,GPIO_PIN_TYPE_INPUT_WITH_INTERRUPT);
reg_gpio_clear_interrupt( BCM5892_GPB26 );
reg_gpio_itr_set_interrupt_type_level( BCM5892_GPB26, GPIO_EDGE_TRIGGER );
reg_gpio_itr_set_interrupt_type( BCM5892_GPB26, GPIO_RISING_EDGE_INTERRUPT_TRIGGER );
reg_gpio_enable_interrupt( BCM5892_GPB26 );


return ;
}




static int msr_probe(struct platform_device *pdev)
{  
int ret = 0;
  dev_t dev = MKDEV(MCR_MAJOR, 0);


hardware_init();


cdev_init(&mcr_cdev, &mcr_fops);

mcr_cdev.owner = THIS_MODULE;
mcr_cdev.ops = &mcr_fops;


if ( cdev_add(&mcr_cdev, dev, 1) )
{
printk("Couldn't register 5892 magic strip card driver\n");
ret = -ENOMEM;
goto out1;
}


if ( (ret = register_chrdev_region(dev, 1, "magic strip card")) < 0)
{
printk("mcr register_chrdev_region error\n");
ret = -ENOMEM;
goto out2;
}


msr_ver = create_proc_entry("strong_lion/version/mcr",0444,NULL);
if (msr_ver == NULL)
{
ret = -ENOMEM;
goto out3;
}
   
msr_ver->data = NULL;
msr_ver->read_proc = &proc_read_msr_ver;


msr_irq=gpio_to_irq (BCM5892_GPB26);


if ( request_irq(msr_irq, msr_interrupt, IRQF_SAMPLE_RANDOM | IRQF_SHARED
, "magic strip card", (void*)pdev) < 0)
{
printk(KERN_ERR "Power : Can't allocate irq %d\n", msr_irq);


ret = -EBUSY;
goto out4;
}


reg_gpio_disable_interrupt( BCM5892_GPB26 );

interrupt_en = 0;


INIT_DELAYED_WORK(&delay_work, msr_interrupt_work_deal);




//init_completion(&data_done); //why put here is not true ?


ret = 0;
goto out1;


out4:
remove_proc_entry("strong_lion/version/mcr",NULL);


out3:
unregister_chrdev_region(dev, 1);
out2:
cdev_del(&mcr_cdev);
out1:

return ret;
}


static int msr_remove(struct platform_device *pdev )
{
dev_t dev = MKDEV(MCR_MAJOR, 0);

printk("i have entered msr_remove\n");


reg_gpio_set_pin( BCM5892_GPB26, 0);

free_irq(msr_irq,  (void*)pdev);


remove_proc_entry("strong_lion/version/mcr",NULL);


unregister_chrdev_region(dev, 1);
cdev_del(&mcr_cdev);


return 0;
}


#ifdef CONFIG_PM
static int msr_suspend(struct platform_device *dev,pm_message_t state)
{
reg_gpio_disable_interrupt( BCM5892_GPB26 );


reg_gpio_set_pin( BCM5892_GPB13, 1); //disable msr

printk("msr_suspend\n");


return 0;
}


static int msr_resume(struct platform_device *dev)
{


hardware_init();


if (atomic_read(&HaveOpen) == MCR_HAVEOPENED)
{
//s3c2410_gpio_setpin(S3C2410_GPD3, 1); /* out 1 */      //power on the MSR chip
}


return 0;
}
#else
#define msr_suspend NULL
#define  NULL
#endif


static struct platform_driver encrypt_msr_driver = {
.probe = msr_probe,
.remove = msr_remove,
.suspend = msr_suspend,
.resume = msr_resume,
.driver = {
.name = "mcr",
},
};


static int __init init_msr(void)
{
printk("init_msr\n");
return platform_driver_register(&encrypt_msr_driver);
}


static void __exit cleanup_msr(void)
{
printk("cleanup_encrypt_msr\n");

platform_driver_unregister(&encrypt_msr_driver);
}




module_init(init_msr);
module_exit(cleanup_msr);


MODULE_AUTHOR("flaming");
MODULE_DESCRIPTION("BCM5892 msr driver for xxx pos");
MODULE_LICENSE("GPL");



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值