现在的位置: 首页 > 综合 > 正文

ic_card 驱动程序开发

2012年01月09日 ⁄ 综合 ⁄ 共 9723字 ⁄ 字号 评论关闭

  IC卡又称集成电路卡,它是在大小和普通信用卡相同的塑料卡片上嵌置一个或多个集成电路构成的。集成电路芯片可以是存储器或向处理器。作为一种身份验证的工具,IC卡经常出现于各种电子设备中,作为一种身份的确认的工具。

  下面以笔者参与的会议系统开发中的ICcard驱动程序为例,介绍linux系统下是如何进行IC card驱动程序开发的。

  1、是ic_card.h文件:

#ifndef IC_CARD
#define IC_CARD

#include
<mach/regs-gpio.h>
#include
<linux/wait.h>
#include
<linux/ioctl.h>

#define IC_CARD_MAJOR 231

#ifndef ICCARD_NR_DEVS
#define ICCARD_NR_DEVS 1 /*设备数*/
#endif

#define IC_RMM_CMD 0x30 //读主存命令字
#define IC_WMM_CMD 0x38 //写主存命令字
#define IC_VER_CMD 0x33 //校验密码
#define IC_RSM_CMD 0x31 //读密码存储区
#define IC_WSM_CMD 0x39 //写密码存储区
#define IC_RPM_CMD 0x34 //读保护存储区
#define IC_WPM_CMD 0x3c //写保护存储区


#define IC_RDSTART_ADDR (volatile unsigned char*)0X26
#define IC_WRSTART_ADDR (volatile unsigned char*)0X26


#define IC_IOCTL_MAGIC 'i'

#define CFG_RD_COUNT _IOW(IC_IOCTL_MAGIC,0,unsigned int)
#define CFG_WR_COUNT _IOW(IC_IOCTL_MAGIC,1,unsigned int)


#define SETB_CARD_CLK() __raw_writel(__raw_readl(S3C2410_GPGDAT)|(1<<0),S3C2410_GPGDAT)
#define CLR_CARD_CLK() __raw_writel(__raw_readl(S3C2410_GPGDAT)&(~(1<<0)),S3C2410_GPGDAT)

#define SETB_CARD_RESRT() __raw_writel(__raw_readl(S3C2410_GPGDAT)|(1<<1),S3C2410_GPGDAT)
#define CLR_CARD_RESRT() __raw_writel(__raw_readl(S3C2410_GPGDAT)&(~(1<<1)),S3C2410_GPGDAT)

#define SETB_CARD_IO() __raw_writel(__raw_readl(S3C2410_GPGDAT)|(1<<3),S3C2410_GPGDAT)
#define CLR_CARD_IO() __raw_writel(__raw_readl(S3C2410_GPGDAT)&(~(1<<3)),S3C2410_GPGDAT)

#define SETB_CARD_POWER() __raw_writel(__raw_readl(S3C2410_GPGDAT)|(1<<7),S3C2410_GPGDAT)
#define CLR_CARD_POWER() __raw_writel(__raw_readl(S3C2410_GPGDAT)&(~(1<<7)),S3C2410_GPGDAT)

wait_queue_head_t r_wait;
//读等待队列
wait_queue_head_t w_wait; //写等待队列

typedef
struct _ic_card_dev
{
unsigned
char* readbufstart; //读入数据缓冲区首指针
// char* readbufend; //读入数据缓冲区末指针
unsigned char* writebufstart; //写入数据缓冲区首指针
// char* writebufend; //写入数据缓冲区末指针
int readcount; //读入数据量
int writecount; //写入数据量
char* readp; //读人数据当前指针
int readnum; //已经读入量
char* writep; //当前写入数据指针
int writenum; //当前写入量
int ic_state; //卡当前状态,O为无卡,1为有卡
int statechange; //卡状态变化标志
int irqno;
int r_press;
int w_press;

}ic_card_dev;

#endif /*IC_CARD*/

  2、实现模块的加载和卸载函数:

1 /*注册设备驱动程序*/
2  static int ic_card_init(void)
3 {
4 int ret;
5 dev_t devno;
6 ICDEBUG(KERN_ALERT "init ic card\n");
7 devno = MKDEV(ic_major, 0);
8 if(IC_CARD_MAJOR)
9 {
10 ret = register_chrdev_region(devno, 1, DEV_NAME);
11 ICDEBUG(KERN_ALERT "register_chrdev_region ret:%d\n",ret);
12 }
13 else
14 {
15 ret=alloc_chrdev_region(&devno, 0, 2, DEV_NAME);
16 ic_major=MAJOR(devno);
17 ICDEBUG(KERN_ALERT "alloc_chrdev_region ret:%d,major:%d\n",ret,ic_major);
18 }
19 if(ret<0)
20 {
21 ICDEBUG(KERN_ALERT "if ret<0 ret:%d\n",ret);
22 return ret;
23 }
24
25 cdev_init(&cdev_ic, &ic_fops);
26 cdev_ic.owner=THIS_MODULE;
27 cdev_ic.ops= &ic_fops;
28
29 //向系统注册该字符设备
30   ret = cdev_add(&cdev_ic, devno, ICCARD_NR_DEVS);
31 ICDEBUG(KERN_ALERT "cdev_add ret:%d\n",ret);
32
33 if (ret)
34 {
35 ICDEBUG("iccard init error\r\n");
36 unregister_chrdev_region(devno,1);
37 goto failregion;
38 }
39
40
41 ic_card_class = class_create(THIS_MODULE, DEV_NAME);
42 if(IS_ERR(ic_card_class))
43 {
44 ICDEBUG("can not creat a ic_card_class class!\n");
45 goto failcls;
46 }
47 device_create(ic_card_class, NULL, MKDEV(IC_CARD_MAJOR, 0), NULL, DEV_NAME);
48
49 /*注册中断*/
50 ret=ic_request_irqs();
51 if(ret<0)
52 {
53 ICDEBUG(KERN_ALERT "ic_card_request_irqs:ret:%d\n",ret);
54 goto faildev;
55 }
56
57 /*初始化时钟*/
58 init_timer(&ic_timer);
59 ic_timer.function=ic_timer_handler;
60
61 spin_lock_init(&lock);
62
63  /* ic_dev_info=kmalloc(ICCARD_NR_DEVS*sizeof(struct ic_card_dev),GFP_KERNEL);
64 if(!ic_dev_info)
65 {
66 ret = -ENOMEM;
67 goto fail;
68 }
69  */
70 //初始化等待对列
71   init_waitqueue_head(&r_wait);
72 init_waitqueue_head(&w_wait);
73 ICDEBUG("ic card init success!\r\n");
74
75 return 0;
76 faildev:
77 ICDEBUG(KERN_ALERT "init ic card fail\n");
78 device_destroy(ic_card_class, MKDEV(IC_CARD_MAJOR, 0));
79 failcls:
80 class_destroy(ic_card_class);
81 failregion:
82 unregister_chrdev_region(devno, 1);
83 return ret;
84
85 }
86
87  /*注销设备驱动程序*/
88  static void ic_card_exit(void)
89 {
90 /*释放中断*/
91 ic_free_irqs();
92
93 cdev_del(&cdev_ic);
94 // kfree(ic_dev_info);
95 device_destroy(ic_card_class, MKDEV(IC_CARD_MAJOR, 0));
96 class_destroy(ic_card_class);
97 unregister_chrdev_region(MKDEV(ic_major,0), 1);
98 ICDEBUG(KERN_ALERT "ic card unregister\n");
99
100 }
101
102 module_init(ic_card_init);
103 module_exit(ic_card_exit);

首先,判断IC_CARD_MAJOR,即是否为设备指定了主设备号,如果IC_CARD_MAJOR不为0,则调用register_chrdev_region()函数注册设备驱动程序。通过register_chrdev_region()函数用于分配指定的设备编号范围。如果申请的设备编号范围跨越了主设备号,它会把分配范围内的编号按主设备号分割成较小的子范围,并在每个子范围上调用 __register_chrdev_region() 。如果其中有一次分配失败的话,那会把之前成功分配的都全部退回。

如果IC_CARD_MAJOR为0,则调用 alloc_chrdev_region()动态分配主设备号给驱动程序。

 linux 2.6 内核采用struct cdev来记录字符设备的信息,通过cdev_init初始化一个静态分配的cdev对象,详细请参考http://www.360doc.com/content/11/0228/12/6030028_96836815.shtml 

调用cdev_add()函数向系统注册该字符设备.

  class_create()函数及device_create()函数使得module被加载时,udev daemon就会自动在/dev下创建IC_CARD设备文件
  然后申请中断,初始化定时器,定时器ic_timer用于消除插卡中的抖动问题,再调用init_waitqueue_head()初始化等待队列。

至此,ic_card驱动程序加载完成。

3、各IC_card操作函数:

static struct file_operations ic_fops={
.open
=ic_open,
.write
=ic_card_wrtie,
.read
=ic_card_read,
.poll
=ic_poll,
.ioctl
=ic_ioctl,
.release
=ic_release,
.fsync
=NULL,
};

具体实现如下:

/*调用ic_request_irqs注册中断处理程序
*配置引脚
*/
int ic_open (struct inode *inode, struct file *filp)
{
int num;
int ret=0;
unsigned
long flags;

ICDEBUG(KERN_ALERT "open ic card\n");
//获取次设备号
num = MINOR(inode->i_rdev);
ICDEBUG(KERN_ALERT
"MINOR:%d\n",num);
if (num >= ICCARD_NR_DEVS)
return -ENODEV;

spin_lock_irqsave(&lock,flags);
filp
->private_data=&ic_dev_info[num];

//检测IC卡是否已插入设备
s3c2410_gpio_cfgpin(S3C2410_GPG6,S3C2410_GPG6_INP); //ICCARD_INTEREPT
if((__raw_readw(S3C2410_GPGDAT)&(1<<6))==0<<6)
{
ic_dev_info[num].ic_state
=1; //代表卡已插入
ic_dev_info[num].r_press=1; //设备可读
ic_dev_info[num].w_press=1; //设备可写
ICDEBUG(KERN_ALERT "has ic card device\n");
}
else
{
ic_dev_info[num].ic_state
=0; //代表卡已插入
ic_dev_info[num].r_press=0; //设备可读
ic_dev_info[num].w_press=0; //设备可写
ICDEBUG(KERN_ALERT "no found ic card device\n");
}
spin_unlock_irqrestore(
&lock,flags);

//初始化输入输出引脚
init_gpio();

ICDEBUG(KERN_ALERT "open ic card success\n");
return ret;
}

int ic_release(struct inode *inode, struct file *filp)
{
//ic_free_irqs();
return 0;
}

/*
*从ic卡中读出一个字节的数据
*/

int ic_card_read_byte(char *ch)
{
int ret=0;
int ii;
for(ii = 8; ii>0; ii--)
{
CLR_CARD_CLK();
udelay(
5);
*ch=(*ch)>>1; //从低位读起
//if((__raw_readw(S3C2410_GPGDAT)&0x0008)==0x0008)
if((__raw_readw(S3C2410_GPGDAT)&(1<<3))==1<<3)
{
*ch|=0x80;
ICDEBUG(KERN_ALERT
"<------------->\n");
}
else
{
ICDEBUG(KERN_ALERT
"<|||||||||||||>\n");
}
udelay(
5);
SETB_CARD_CLK();
}

ICDEBUG(KERN_ALERT "ic_card_read_byte:ch is>>>>>(%c)\n",*ch);
return ret;
}

int ic_card_write_byte(char *ch)
{
int ret=0;
int ii;

ICDEBUG(KERN_ALERT "enter ic_card_write_byte,ch is %c\n",*ch);
for(ii= 0; ii<8; ii++)
{
CLR_CARD_CLK();
udelay(
5);
if(*ch&0x01)
{
ICDEBUG(KERN_ALERT
"[+++++$++++++++]\n");
SETB_CARD_IO();
//输入1
}
else
{
ICDEBUG(KERN_ALERT
"[-----$--------]\n");
CLR_CARD_IO();
//输入0
}
udelay(
5);
SETB_CARD_CLK();
udelay(
10);
*ch=*ch>>1;

}
return ret;

}

/*
*复位和复位应答
*/
static int ic_card_reset(void)
{
unsigned
char temp_ch;
int temp_i = 4;
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_OUTP);
//OUT
udelay(5);
CLR_CARD_RESRT();
CLR_CARD_CLK();
SETB_CARD_IO();
udelay(
5);
SETB_CARD_RESRT();
udelay(
5);
SETB_CARD_CLK();
udelay(
30);
CLR_CARD_CLK();
udelay(
5);
CLR_CARD_RESRT();
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_INP);
//IN
udelay(10);
do{
//temp_ch = ic_card_read_byte();
ic_card_read_byte(&temp_ch);
ICDEBUG(KERN_ALERT
"ic_card_reset:temp_ch is(%c)\n",temp_ch);
}
while(--temp_i>0);

CLR_CARD_CLK();
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_OUTP); //IN
udelay(5);
SETB_CARD_IO();
udelay(
5);
CLR_CARD_CLK();
udelay(
5);
return 0;
}

/*
*命令开始条件
*/
void ic_card_start_cmd(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_OUTP);
//out
CLR_CARD_CLK();
SETB_CARD_IO();
udelay(
5);
SETB_CARD_CLK();
udelay(
5);
CLR_CARD_IO();
udelay(
5);
}

/*
*命令结束条件
*/
void ic_card_end_cmd(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_OUTP);
CLR_CARD_CLK();
CLR_CARD_IO();
udelay(
5);
SETB_CARD_CLK();
udelay(
5);
SETB_CARD_IO();
udelay(
5);
}

/*发送命令*/
void ic_card_send_cmd(const char cmd,const char addr,const char count)
{
ICDEBUG(KERN_ALERT
"enter ic_card_read:cmd is %c,addr is %c,count is %c\n",cmd,addr,count);
ic_card_start_cmd();
ic_card_write_byte(
&cmd);
ic_card_write_byte(
&addr);
ic_card_write_byte(
&count);
ic_card_end_cmd();
}

void ic_card_breakoperator(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_OUTP);
CLR_CARD_CLK();
CLR_CARD_RESRT();
CLR_CARD_IO();
udelay(
5);
SETB_CARD_RESRT();
SETB_CARD_IO();
udelay(
5);
CLR_CARD_RESRT();
udelay(
5);
}

/*从设备中读取指定长度的数据*/
ssize_t ic_dev_read(
struct file *filep,const char *buf, size_t count, loff_t *offset)
{
int ret=0;
// wait_event_interruptible();
//char *kbuf;
int istate;
int sizetmp;
char* pbuf;
//unsigned char ch=0;

ic_card_dev
* icdev=(ic_card_dev*)filep->private_data;
ICDEBUG(KERN_ALERT
"enter ic_dev_read\n");
istate
= icdev->ic_state;
ICDEBUG(KERN_ALERT
"ic_dev_istate:%d\n",istate);
pbuf
=buf;
if(!istate)
{
return -ENODEV;
}

if(!pbuf)
{
return -1;
}

sizetmp=count;

s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_INP); //将GPG3配置成输入引脚

CLR_CARD_CLK();
udelay(
5);
do{
ic_card_read_byte(pbuf
++);
//*buf++ = ic_card_read_byte();
ret++;
ICDEBUG(KERN_ALERT
"[ic_card_read:buf is (%c) ret:%d]\n",*(pbuf-1),ret);
}
while(--sizetmp);

return ret;

}

/*往设备中写入数据*/
ssize_t ic_dev_wrtie(
struct file *filep, char *buf, size_t count, loff_t *offset)
{
int ret = 0;
int istate;
unsigned
long flags;
int sizetmp;

ICDEBUG(KERN_ALERT "enter ic_dev_wrtie\n");
spin_lock_irqsave(
&lock,flags);
istate
= ((ic_card_dev*)(filep->private_data))->ic_state;
spin_unlock_irqrestore(
&lock,flags);

if(!istate)
{
return -ENODEV;
}
if(!buf)
return -1;
// wait_event_interruptible();

s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_OUTP);
//将GPG3配置成输出引脚

sizetmp
=count;
do
{
ic_card_write_byte(buf
++); //按字节发送至ic卡
}while(--sizetmp);
return ret;
}

/*file_operations read*/
ssize_t ic_card_read(
struct file *filep, char __user *buf, size_t count, loff_t *offset)
{
//int ii;
int ret;
char* kbuf;
unsigned
long flags;
int r_press;

ICDEBUG(KERN_ALERT "enter ic_card_read\n");

spin_lock_irqsave(&lock,flags);
r_press
=((ic_card_dev*)filep->private_data)->r_press;
spin_unlock_irqrestore(
&lock,flags);

ICDEBUG(KERN_ALERT "ic_card_read:r_press is:%d\n",r_press);

wait_event_interruptible(r_wait, r_press!=0);

kbuf=kmalloc(count,GFP_KERNEL);
if(!kbuf)
{
return -ENOMEM;
}
spin_lock_irqsave(
&lock,flags);
((ic_card_dev
*

抱歉!评论已关闭.