您的位置:首页 > 其它

tiny6410按键platform(平台)驱动的实现

2014-09-11 14:40 405 查看
tiny6410中的按键驱动没有提供按键的platform驱动,于是闲来无事把/drivers/char/mini6410_buttons.c给移植成platform驱动,下面是整个的移植过程:

1.首先在 /arch/arm/mach-s3c64xx 目录下添加我们的按键device,文件名定为dev-buttons.c,其源码为:

#include <linux/module.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/interrupt.h>

#include <linux/device.h>

#include <plat/devs.h>//这个是必须添加的,否则会产生错误

/* 平台资源的定义 */

static struct resource tiny6410_buttons_resource[] = {

[0] = {

.start = IRQ_EINT(0),

.end = IRQ_EINT(0),

.flags = IORESOURCE_IRQ,

},

[1] = {

.start = IRQ_EINT(1),

.end = IRQ_EINT(1),

.flags = IORESOURCE_IRQ,

},

[2] = {

.start = IRQ_EINT(2),

.end = IRQ_EINT(2),

.flags = IORESOURCE_IRQ,

},

[3] = {

.start = IRQ_EINT(3),

.end = IRQ_EINT(3),

.flags = IORESOURCE_IRQ,

},

[4] = {

.start = IRQ_EINT(4),

.end = IRQ_EINT(4),

.flags = IORESOURCE_IRQ,

},

[5] = {

.start = IRQ_EINT(5),

.end = IRQ_EINT(5),

.flags = IORESOURCE_IRQ,

},

[6] = {

.start = IRQ_EINT(19),

.end = IRQ_EINT(19),

.flags = IORESOURCE_IRQ,

},

[7] = {

.start = IRQ_EINT(20),

.end = IRQ_EINT(20),

.flags = IORESOURCE_IRQ,

} /* 这里不需要加逗号 */

};

struct platform_device tiny6410_buttons_device = //此处不要定义为static的,否则会有错误

{

.name = "tiny6410_buttons",

.id = -1,

.num_resources = ARRAY_SIZE(tiny6410_buttons_resource),

.resource = tiny6410_buttons_resource,

};

2.需要对/arch/arm/mach-s3c64xx 目录下的Makefile和Kconfig进行修改:

makefile的最后添加这样一行代码:

obj-y += dev-buttons.o

这里-y表示不管在make menuconfig中有没有选择都会强制编译

Kconfig的最后添加:

config BUTTONS_TINY6410

bool "Buttons_tiny6410"

help

Machine support for the Buttons_tiny6410

3.修改/arch/arm/mach-s3c64xx 目录下的 mach-mini6410.c的代码:

在此结构体中 static struct platform_device *mini6410_devices[] __initdata = { 最后一行添加按键设备:

&s3c_device_ts

此结构会被添加到static void __init mini6410_machine_init(platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));)中,此函数会在内核启动初始化时被调用,从而将按键device挂载到内核,等待驱动去匹配。(注意:驱动的name要和device的name一样,这样才能进行匹配)

4.我们还有在/arch/arm/plat-samsung/include/plat/文件中声明我们的platform设备:

在其中添加 extern struct platform_device tiny6410_buttons_device;

至此,平台设备这一边已经告一段落了!下面就是按键驱动。

驱动以模块方式添加到内核,下面是驱动的代码,文件名为:plat_btn_drv.c,

#include <linux/module.h>

#include <linux/types.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/interrupt.h>

#include <linux/uaccess.h>

#include <linux/io.h>

#include <mach/map.h>

#include <mach/regs-gpio.h>

#include <linux/poll.h>

#include <linux/irq.h>

#include <asm/unistd.h>

#include <linux/device.h>

#include <mach/gpio-bank-n.h>

#include <mach/gpio-bank-l.h>

#define DRIVER_NAME "tiny6410_buttons"

#define DEVICE_NAME "tiny6410_buttons"

/* 定义并初始化等待队列 */

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

static volatile int ev_press = 0;

/* 记录键值 */

static int key_value;

/* 记录按键中断号 */

typedef struct

{

int irq; /* 中断号,初始化为 0,将在

* probe 获取资源 */

int num; /* 对应的按键编号 */

char *name; /* 中断所属的名字 */

} button_irq_t;

button_irq_t button_irqs[] =

{

{0, 0, "KEY0"},

{0, 1, "KEY1"},

{0, 2, "KEY2"},

{0, 3, "KEY3"},

{0, 4, "KEY4"},

{0, 5, "KEY5"},

{0, 6, "KEY6"},

{0, 7, "KEY7"},

};

/*

* buttons_interrupt

* 使用一个整形变量 key_value 的 0~7 位来记录键值,0~7

* 位分别对应 KEY0~KEY7 的抬起或者按下情况( 1 表示按下)。

*/

static irqreturn_t buttons_interrupt(int irq,void *dev_id)

{

/* 定义一个指针,指向所对应的中断号 */

button_irq_t *button_irqs = (button_irq_t *)dev_id;

int down;

int num;

unsigned tmp;

num = button_irqs->num;

switch(num)

{

case 0: case 1: case 2: case 3: case 4: case 5:

tmp = readl(S3C64XX_GPNDAT);

down = !(tmp & (1 << num));

break;

case 6: case 7:

tmp = readl(S3C64XX_GPLDAT);

down = !(tmp & (1 << (num + 5)));

break;

default:

down = 0;

}

if(down == !(key_value & (1 << num)))

{

key_value = down ? key_value | (1<<num) : key_value & ~(1 << num);

ev_press = 1;

wake_up_interruptible(&button_waitq);

}

return IRQ_RETVAL(IRQ_HANDLED);

}

/*

* tiny6410_buttons_open

*/

static int tiny6410_buttons_open(struct inode *inode,struct file *file)

{

int i;

int err = 0;

for(i = 0;i < sizeof(button_irqs) / sizeof(button_irqs[0]);i ++ )

{

if (button_irqs[i].irq < 0)

continue;

/* 申请中断 */

err = request_irq(button_irqs[i].irq,buttons_interrupt,

IRQ_TYPE_EDGE_BOTH,

button_irqs[i].name,

(void *)&button_irqs[i]);

if (err)

break;

}

if(err)

{

i--;

for(;i >= 0;i -- )

{

if(button_irqs[i].irq < 0)

continue;

disable_irq(button_irqs[i].irq);

free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);

}

return -EBUSY;

}

ev_press = 1;

return 0;

}

/*

* tiny6410_buttons_close

*/

static int tiny6410_buttons_close(struct inode *inode,struct file *file)

{

int i;

for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i ++ )

{

if(button_irqs[i].irq < 0)

continue;

free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);

}

return 0;

}

/*

* tiny6410_buttons_read

*/

static int tiny6410_buttons_read(struct file *filp,char __user *buff,

size_t count,loff_t *offp)

{

unsigned long err;

if(!ev_press)

{

if(filp->f_flags & O_NONBLOCK)

return -EAGAIN;

else

wait_event_interruptible(button_waitq,ev_press);

}

ev_press = 0;

err = copy_to_user((void *)buff,(const void *)(&key_value),

min(sizeof(key_value),count));

return err ? -EFAULT : min(sizeof(key_value),count);

}

/*

* poll 实现函数

*/

static unsigned int tiny6410_buttons_poll(struct file *file,

struct poll_table_struct *wait)

{

unsigned int mask = 0;

poll_wait(file,&button_waitq,wait);

if(ev_press)

mask |= POLLIN | POLLRDNORM;

return mask;

}

/*

* file_operation

*/

static struct file_operations dev_fops =

{

.owner = THIS_MODULE,

.open = tiny6410_buttons_open,

.release = tiny6410_buttons_close,

.read = tiny6410_buttons_read,

.poll = tiny6410_buttons_poll,

};

/*

* 混合设备结构体

*/

static struct miscdevice tiny6410_buttons_misc =

{

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &dev_fops,

};

/*

* probe 实现函数

*/

static int tiny6410_buttons_probe(struct platform_device *pdev)

{

int ret;

int i;

struct device *dev;

static struct resource *buttons_irq;

printk("[call %s]\n", __func__);

/* 获取设备资源 */

for(i = 0;i < 8;i ++ )

{

buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);

button_irqs[i].irq = buttons_irq->start;

}

ret = misc_register(&tiny6410_buttons_misc);

return 0;

}

/*

* remove 实现函数

*/

static int tiny6410_buttons_remove(struct platform_device *dev)

{

misc_deregister(&tiny6410_buttons_misc);

return 0;

}

/* 平台设备驱动结构 */

static struct platform_driver tiny6410_buttons_driver = {

.probe = tiny6410_buttons_probe,

.remove = tiny6410_buttons_remove,

.driver =

{

.owner = THIS_MODULE,

.name = DRIVER_NAME,

},

};

static int __init buttons_init(void)

{

printk("[Call buttons_init!]\n");

/* 注册驱动 */

platform_driver_register(&tiny6410_buttons_driver);

return 0;

}

static void __exit buttons_exit(void)

{

printk("[Call buttons_exit!]\n");

platform_driver_unregister(&tiny6410_buttons_driver);

}

module_init(buttons_init);

module_exit(buttons_exit);

MODULE_AUTHOR("_Justin");

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("Tiny6410 Buttons Driver");

最后我们需要重新编译内核:make zImage

然后将生成的zImage拷贝到开发板上,运行,编写按键驱动的makefile:

ifneq ($(KERNELRELEASE),)

obj-m := plat_btn_drv.o

else

KDIR := /opt/FriendlyARM/mini6410/linux/linux-2.6.38

all:

make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-

clean:

rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order

endif

最后把驱动的plat_btn_drv.ko文件通过拷贝到开发板,通过命令insmod plat_btn_drv.ko插入内核:

此时会在超级终端中打印出下面的话:

[Call buttons_init!]

[call tiny6410_buttons_probe]

表明platform驱动成功加载,

这时候,在/sys/bus/platform/devices下,我们发现我们添加的设备tiny6410_buttons已经存在了。

另外,在/sys/bus/platform/drivers下,我们发现我们添加的驱动[b]tiny6410_buttons也已经存在了。[/b]

在/sys/bus/platform/devices/[b]tiny6410_buttons/driver下,有设备tiny6410_buttons,这说明tiny6410_buttons设备和tiny6410_buttons驱动已经联系起来了。[/b]

另外,在/sys/bus/platform/drivers/[b]tiny6410_buttons/device下,有驱动tiny6410_buttons,这也说明tiny6410_buttons设备和tiny6410_buttons驱动已经联系起来了。[/b]

我们可以写一个测试程序测试一下:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/select.h>

#include <time.h>

#define DEVICE_NAME "/dev/tiny6410_buttons"

static int key_value = 0;

int main(void)

{

int fd, ret;

fd_set rfds;

int last_kval = key_value;

if(-1 == (fd = open(DEVICE_NAME,O_RDONLY)))

{

printf("open %s error\n",DEVICE_NAME);

_exit(EXIT_FAILURE);

}

/* 先清空集合 */

FD_ZERO(&rfds);

/* 设置要监控的文件描述符 */

FD_SET(fd,&rfds);

printf("Test for tiny6410_buttons: ...\n");

while(1)

{

if(-1 == (ret = select(fd + 1,&rfds,NULL,NULL,NULL)))

{

printf("select error\n");

_exit(EXIT_FAILURE);

}

if(FD_ISSET(fd,&rfds))

{

read(fd, &key_value, sizeof(key_value));

int i;

for(i = 0;i < 8;i ++ )

{

if((key_value & (1 << i)) != (last_kval & (1 << i)))

{

printf("KEY%d: %s (key_value=0x%x)\n", i+1,

(key_value& (1<<i))? "DOWN": "UP", key_value);

}

}

last_kval = key_value;

}

}

_exit(EXIT_SUCCESS);

}

运行测试程序会打印出:
KEY4: DOWN (key_value=0x8)

KEY4: UP (key_value=0x0)

KEY1: DOWN (key_value=0x1)

KEY1: UP (key_value=0x0)

KEY2: DOWN (key_value=0x2)

KEY2: UP (key_value=0x0)

KEY4: DOWN (key_value=0x8)

KEY4: UP (key_value=0x0)

KEY6: DOWN (key_value=0x20)

KEY6: UP (key_value=0x0)

。。。。。。。。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: