/*
* 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");
* 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");